package com.chenfan.mcn.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.mcn.clients.baseinfo.BaseCustomer;
import com.chenfan.mcn.clients.baseinfo.DescByCodeDTO;
import com.chenfan.mcn.clients.finance.FinanceInvoiceDTO;
import com.chenfan.mcn.clients.privilege.*;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.mcn.constant.*;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.ApprovalEnum;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.event.EventPublisher;
import com.chenfan.mcn.event.OperateLogEvent;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.common.extension.dict.DictStream;
import com.chenfan.common.extension.dict.DictTranslationUtils;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import com.chenfan.common.extension.validation.groups.Modify;
import com.chenfan.mcn.component.CodeGenerateHelper;
import com.chenfan.common.extension.lock.DistributedLockTemplate;
import com.chenfan.mcn.model.*;
import com.chenfan.common.config.Constant;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.finance.FinanceClient;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.dao.ContractExcutionOrderMapper;
import com.chenfan.mcn.dao.StarMonthlySettlementDetailMapper;
import com.chenfan.mcn.dao.StarMonthlySettlementMapper;
import com.chenfan.mcn.dao.StarMonthlySettlementSubMapper;
import com.chenfan.mcn.model.ContractExcutionOrder;
import com.chenfan.mcn.model.StarMonthlySettlement;
import com.chenfan.mcn.model.StarMonthlySettlementDetail;
import com.chenfan.mcn.model.StarMonthlySettlementSub;
import com.chenfan.mcn.model.common.KVPair;
import com.chenfan.mcn.model.dto.*;
import com.chenfan.mcn.model.rpc.ChargeClearCallback;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.mq.producer.StarMonthlySettlementMessageProducer;
import com.chenfan.mcn.extension.rule.ComputableRuleEngine;
import com.chenfan.mcn.rule.ShareTaxAmountContext;
import com.chenfan.mcn.rule.ShareTaxAmountRule;
import com.chenfan.mcn.service.*;
import com.chenfan.mcn.utils.*;
import com.chenfan.process.client.ProcessClient;
import com.chenfan.process.dto.ApprovalOperationDTO;
import com.chenfan.process.vo.ApprovalNodeVO;
import com.chenfan.process.vo.ApprovalOperationVO;
import com.chenfan.process.vo.NextNotifyVo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 红人月度结算单 服务实现类
 * </p>
 *
 * @author wulg
 * @since 2022-01-13
 */
@Slf4j
@Service
public class StarMonthlySettlementServiceImpl implements StarMonthlySettlementService, ApprovalCallbackService {

    @Autowired
    private StarMonthlySettlementMapper settlementMapper;

    @Autowired
    private StarMonthlySettlementDetailMapper settlementDetailMapper;

    @Autowired
    private StarMonthlySettlementSubMapper settlementSubMapper;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private ContractExcutionOrderMapper excutionOrderMapper;

    @Autowired
    private CalculationDevidedMapper calculationDevidedMapper;

    @Autowired
    private StarPlatformInfoService starPlatformInfoService;

    @Autowired
    private StarAccountInfoService starAccountInfoService;

    @Autowired
    private ApprovalFlowService approvalFlowService;

    @Autowired
    private StarBasicDataMapper starBasicDataMapper;

    @Autowired
    private MessageInfoService messageInfoService;

    @Autowired
    private StarMonthlySettlementMessageProducer messageProducer;

    @Autowired
    private FinanceClient financeClient;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private ProcessClient processClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ContractExcutionOrderService contractExcutionOrderService;

    @Autowired
    private DocIntentionOrderMapper intentionOrderMapper;

    @Autowired
    private BrandInfoService brandInfoService;

    private static final String APPROVAL_KEY = Constant.AUTHORIZATION + ":" + "approval::star_monthly_settlement::";

    @Override
    public Page<StarMonthlySettlementListVO> getPage(StarMonthlySettlementSearchDTO searchDTO) {
        searchDTO.setAlias("sms.");
        searchDTO.setProcessIds(Arrays.asList(ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId()));
        if (CollectionUtils.isNotEmpty(searchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(searchDTO.getFlowStatus(), searchDTO.getProcessIds());
            if (CollectionUtils.isEmpty(allList)) {
                return new Page<>();
            }
            searchDTO.setSrcIds(allList);
        }
        Page<StarMonthlySettlementListVO> settlementPage = settlementMapper.getPage(new Page<>(searchDTO.getPageNum(), searchDTO.getPageSize()), searchDTO);
        List<StarMonthlySettlementListVO> settlementList = settlementPage.getRecords();
        if (CollectionUtils.isNotEmpty(settlementList)) {
            //查询FlowId
            List<Long> idList = settlementList.stream().map(StarMonthlySettlementListVO::getId).collect(Collectors.toList());
            Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, searchDTO.getProcessIds());
            if (MapUtils.isNotEmpty(flowMap)) {
                settlementList.forEach(contract -> {
                    contract.setFlowId(flowMap.get(contract.getId()));
                });
            }
            List<Long> flowList = settlementList.stream().map(StarMonthlySettlementListVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
            JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
            settlementList.forEach(item -> {
                item.setFlowStatusName(CommonUtil.defaultString(flowMapping, item.getFlowId()));
            });
        }
        return settlementPage;
    }

    @Override
    public Long addSettlement(StarMonthlySettlementSaveDTO saveDTO) {
        StarMonthlySettlement starMonthlySettlement = new StarMonthlySettlement();
        starMonthlySettlement.setStarId(saveDTO.getStarId());
        starMonthlySettlement.setSettlementCode(CodeGenerateHelper.getCode(BillCodeCst.STAR_MONTHLY_SETTLEMENT));
        starMonthlySettlement.setSettlementDate(DateUtil.getNowYearMonth());
        starMonthlySettlement.setOnlinePaidStatus(PaidStatusEnum.UN_PAYBACK.getCode());
        starMonthlySettlement.setOfflinePaidStatus(PaidStatusEnum.UN_PAYBACK.getCode());
        starMonthlySettlement.setIsOfflineReimburse(NumberCst.ZERO);
        boolean result = settlementMapper.insert(starMonthlySettlement) > 0;
        return starMonthlySettlement.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modifySettlement(StarMonthlySettlementSaveDTO saveDTO) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(saveDTO.getId(), true);
        if (StarMonthlySettlementStatusEnum.isApproval(saveDTO.getApprovalStatus())) {
            //参数校验后置
            StarBasicData starBasicData = starBasicDataMapper.selectById(starMonthlySettlement.getStarId());
            if(!(Objects.nonNull(starBasicData) && StarTypeEnum.KOC.getCode().equals(starBasicData.getStarType()))) {
                BusinessAssert.notBlank(saveDTO.getConfirmScreenshot(), McnErrorCode.PARAM_ERROR, "信息确认截图不能为空");
            }
        }
        this.verifyApprovalStatus(starMonthlySettlement);
        StarMonthlySettlementStatusEnum statusEnum = StarMonthlySettlementStatusEnum.isApproval(saveDTO.getApprovalStatus())
                ? StarMonthlySettlementStatusEnum.APPROVAL : StarMonthlySettlementStatusEnum.UN_COMMIT;
        boolean result = settlementMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlement.class)
                //.set(StarMonthlySettlement::getStarId, saveDTO.getStarId())
                .set(StarMonthlySettlement::getApprovalStatus, statusEnum.getCode())
                .set(StarMonthlySettlement::getAttachmentFile, saveDTO.getAttachmentFile())
                .set(StarMonthlySettlement::getConfirmScreenshot, saveDTO.getConfirmScreenshot())
                .set(StarMonthlySettlement::getSettlementDate, saveDTO.getSettlementDate())
                .set(StarMonthlySettlement::getIsOfflineReimburse, saveDTO.getIsOfflineReimburse())
                .set(StarMonthlySettlement::getStarAccountId, saveDTO.getStarAccountId())
                .set(StarMonthlySettlement::getRemark, saveDTO.getRemark())
                .set(StarMonthlySettlement::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlement::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlement::getUpdateDate, new Date())
                .eq(StarMonthlySettlement::getId, saveDTO.getId()));
        if (result) {
            StarMonthlySettlement newStarMonthlySettlement = this.getSettlement(saveDTO.getId(), false);
            if (StarMonthlySettlementStatusEnum.isApproval(newStarMonthlySettlement.getApprovalStatus())) {
                BusinessAssert.isTrue(settlementDetailMapper.selectCount(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                                .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId()).eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)) > 0
                        , McnErrorCode.PARAM_ERROR, "未关联执行单-不允许提交审批！");
                //结算单-拆单
                this.splitSettlement(newStarMonthlySettlement);
                stringRedisTemplate.opsForValue().set(APPROVAL_KEY + newStarMonthlySettlement.getSettlementCode(), JSONObject.toJSONString(UserVoContextHolder.getUserVo()), 100, TimeUnit.DAYS);
                approvalFlowService.startProcess(newStarMonthlySettlement.getId(), newStarMonthlySettlement.getSettlementCode(), ApprovalEnum.STAR_MONTHLY_SETTLEMENT, JSON.toJSONString(newStarMonthlySettlement));
            }
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlement, newStarMonthlySettlement)
                    .build());
        }
        return result;
    }

    @Override
    public Page<StarMonthlySettlementExcutionOrderVO> getExcutionOrders(StarMonthlySettlementExcutionOrderQueryDTO queryDTO) {
        queryDTO.setApprovalStatus(ExcutionApprovalStatusEnum.PASSED.getCode());
        Page<StarMonthlySettlementExcutionOrderVO> excutionOrderPage = settlementDetailMapper.getExcutionOrders(
                new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()), queryDTO);
        List<StarMonthlySettlementExcutionOrderVO> excutionOrders = excutionOrderPage.getRecords();
        if (CollectionUtils.isNotEmpty(excutionOrders)) {
            List<String> brandCodes = excutionOrders.stream().map(StarMonthlySettlementExcutionOrderVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            //查询红人平台信息
            Map<Long, StarPlatInfoVO> starPlatInfoVoMap = this.getStarPlatInfoVoMap(excutionOrders, StarMonthlySettlementExcutionOrderVO::getStarPlatformInfoId);
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
            excutionOrders.forEach(e -> {
                if(brandMap.containsKey(e.getBrandName())) {
                    e.setBrandName(brandMap.get(e.getBrandName()));
                }
                if (CommonUtil.containsKey(starPlatInfoVoMap, e.getStarPlatformInfoId())) {
                    StarPlatInfoVO starPlatInfoVO = starPlatInfoVoMap.get(e.getStarPlatformInfoId());
                    e.setPlatformId(starPlatInfoVO.getPlatformId());
                    e.setPlatformName(starPlatInfoVO.getPlatformName());
                    e.setStarNickName(starPlatInfoVO.getPlatNickName());
                    if (StringUtils.isNotBlank(e.getPublishForm())) {
                        e.setPublishForm(CommonUtil.getMapValue(secondlevelDictMap.get(e.getPlatformId()), e.getPublishForm()));
                    }
                }
            });
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(DictStream.map(DictTypeCst.RELEASE_TYPE, StarMonthlySettlementExcutionOrderVO::getPublishType, StarMonthlySettlementExcutionOrderVO::setPublishType)
                            ), (dictProfileList, dictList) -> baseInfoClient.getDescByCode(new DescByCodeDTO().setDictsCodes(dictList).setProfileCodes(dictProfileList)).getObj(), excutionOrders);
        }
        return excutionOrderPage;
    }

    @Override
    public Page<StarMonthlySettlementDetailListVO> getDetailPage(StarMonthlySettlementDetailQueryDTO queryDTO) {
        Page<StarMonthlySettlementDetailListVO> detailPage = settlementDetailMapper.getDetailPage(
                new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()), queryDTO);
        List<StarMonthlySettlementDetailListVO> detailList = detailPage.getRecords();
        if (CollectionUtils.isNotEmpty(detailList)) {
            List<String> brandCodes = detailList.stream().map(StarMonthlySettlementDetailListVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            Map<Long, String> companyMap = CommonUtil.defaultList(privilegeClient.getParList().getObj()).stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
            //查询红人平台信息
            Map<Long, StarPlatInfoVO> starPlatInfoVoMap = this.getStarPlatInfoVoMap(detailList, StarMonthlySettlementDetailListVO::getStarPlatformInfoId);
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
            detailList.forEach(detail -> {
                if(brandMap.containsKey(detail.getBrandName())) {
                    detail.setBrandName(brandMap.get(detail.getBrandName()));
                }
                detail.setCompanyContractSubject(companyMap.get(detail.getContractingId()));
                if (CommonUtil.containsKey(starPlatInfoVoMap, detail.getStarPlatformInfoId())) {
                    StarPlatInfoVO starPlatInfoVO = starPlatInfoVoMap.get(detail.getStarPlatformInfoId());
                    detail.setPlatformName(starPlatInfoVO.getPlatformName());
                    detail.setStarNickname(starPlatInfoVO.getPlatNickName());
                    detail.setPublishFormName(CommonUtil.getMapValue(secondlevelDictMap.get(starPlatInfoVO.getPlatformId()), detail.getPublishForm()));
                }
            });
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(
                    DictStream.map(DictTypeCst.RELEASE_TYPE, StarMonthlySettlementDetailListVO::getPublishType, StarMonthlySettlementDetailListVO::setPublishType)
                    ), (dictProfileList, dictList) -> baseInfoClient.getDescByCode(new DescByCodeDTO().setDictsCodes(dictList).setProfileCodes(dictProfileList)).getObj(),
                    detailList);
        }
        return detailPage;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addDetails(StarMonthlySettlementDetailAddDTO dto) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(dto.getSettlementId(), true);
        this.verifyApprovalStatus(starMonthlySettlement);
        return this.addDetailsIfNecessary(starMonthlySettlement, dto, null, true);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modifyDetail(StarMonthlySettlementDetailModifyDTO dto) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(dto.getSettlementId(), true);
        this.verifyApprovalStatus(starMonthlySettlement);
        boolean result = settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                .set(StarMonthlySettlementDetail::getSettlementForm, dto.getSettlementForm())
                .set(StarMonthlySettlementDetail::getRemark, dto.getRemark())
                .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId())
                .eq(StarMonthlySettlementDetail::getId, dto.getId()));
        if (result) {
            
            StarMonthlySettlement newStarMonthlySettlement = settlementMapper.selectById(starMonthlySettlement.getId());
            EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlement, newStarMonthlySettlement)
                    .build());
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteDetails(StarMonthlySettlementDetailDeleteDTO dto) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(dto.getSettlementId(), true);
        this.verifyApprovalStatus(starMonthlySettlement);
        boolean result = settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                .set(StarMonthlySettlementDetail::getIsDelete, NumberCst.ONE)
                .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId())
                .in(StarMonthlySettlementDetail::getId, dto.getDetailIds()));
        if (result) {
            StarMonthlySettlement newStarMonthlySettlement = settlementMapper.selectById(starMonthlySettlement.getId());
            EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlement, newStarMonthlySettlement)
                    .build());
        }
        return result;
    }

    @Override
    public String importDetails(Long id, List<RelatedExcutionOrderInputDTO> inputList) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(id, true);
        inputList = CommonUtil.defaultList(inputList).stream().filter(t -> StringUtils.isNotBlank(t.getExcuteCode())).collect(Collectors.toList());
        BusinessAssert.notEmpty(inputList, McnErrorCode.IMPORT_CONTENT_EMPTY);
        List<String> excuteCodes = inputList.stream().map(RelatedExcutionOrderInputDTO::getExcuteCode).distinct().collect(Collectors.toList());
        //筛出有重复的执行单号
        List<String> repeatedExcuteCodes = inputList.stream().collect(Collectors.groupingBy(RelatedExcutionOrderInputDTO::getExcuteCode, Collectors.counting()))
                .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList());
        //查询执行单
        List<ContractExcutionOrder> excutionOrderList = CommonUtil.defaultList(excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getExcuteCode, excuteCodes).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO)));
        //查询已添加的执行单
        List<Long> existedExcutionOrderIds = CommonUtil.defaultList(settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .select(StarMonthlySettlementDetail::getExcutionOrderId).eq(StarMonthlySettlementDetail::getSettlementId, id)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO).eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)))
                .stream().map(StarMonthlySettlementDetail::getExcutionOrderId).collect(Collectors.toList());
        List<RelatedExcutionOrderOutputDTO> outputList = verifyImportExcutionOrder(inputList, starMonthlySettlement, excutionOrderList, repeatedExcuteCodes, existedExcutionOrderIds);
        List<RelatedExcutionOrderOutputDTO> errorList = outputList.stream().filter(data -> StringUtils.isNotBlank(data.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(errorList)) {
            String fileId = ImportExcelEnum.SETTLEMENT_EXCUTION_ORDER.getFileId();
            stringRedisTemplate.opsForValue().set(McnConstant.CACHE_PRIFIX + fileId, JSONObject.toJSONString(outputList), 30, TimeUnit.DAYS);
            return fileId;
        }
        List<RelatedExcutionOrderOutputDTO> sucessList = outputList.stream().filter(data -> Objects.nonNull(data.getExcuteId())).collect(Collectors.toList());
        //插入执行单数据
        if (CollectionUtils.isNotEmpty(sucessList)) {
            List<StarMonthlySettlementDetail> detailList = new ArrayList<>(excutionOrderList.size());
            sucessList.forEach(e -> {
                StarMonthlySettlementDetail detail = new StarMonthlySettlementDetail();
                detail.setSettlementId(starMonthlySettlement.getId());
                detail.setExcutionOrderId(e.getExcuteId());
                detail.setContractingId(e.getContractingId());
                detail.setFinanceDevidedAmount(e.getFinanceDevidedAmount());
                detail.setSettlementForm(e.getSettlementForm());
                detail.setIsInvalid(NumberCst.ZERO);
                detailList.add(detail);
            });
            settlementDetailMapper.insertBatch(detailList);
        }
        return null;
    }

    /**
     * 校验Excel导入的执行单
     *
     * @param inputList
     * @param starMonthlySettlement
     * @param excutionOrderList
     * @param repeatedExcuteCodes
     * @param existedExcutionOrderIds
     * @return
     */
    private List<RelatedExcutionOrderOutputDTO> verifyImportExcutionOrder(List<RelatedExcutionOrderInputDTO> inputList, StarMonthlySettlement starMonthlySettlement, List<ContractExcutionOrder> excutionOrderList, List<String> repeatedExcuteCodes, List<Long> existedExcutionOrderIds) {
        List<Long> excutionOrderIds = CommonUtil.defaultList(excutionOrderList.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList()), -1L);
        List<Long> incomeContractIds = CommonUtil.defaultList(excutionOrderList.stream().map(ContractExcutionOrder::getIncomeContractId).distinct().collect(Collectors.toList()), -1L);
        Map<String, ContractExcutionOrder> excutionOrderMap = excutionOrderList.stream().collect(Collectors.toMap(k -> k.getExcuteCode(), v -> v));
        //查询已关联的执行单
        List<Long> relatedExcutionOrderIds = CommonUtil.defaultList(settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .select(StarMonthlySettlementDetail::getExcutionOrderId).in(StarMonthlySettlementDetail::getExcutionOrderId, excutionOrderIds)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO).eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)))
                .stream().map(StarMonthlySettlementDetail::getExcutionOrderId).collect(Collectors.toList());
        //查询执行单关联的计算分成信息
        Map<Long, CalculationDevided> calculationDevidedMap = CommonUtil.defaultList(
                calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class).in(CalculationDevided::getExcutionOrderId, excutionOrderIds)
                        .eq(CalculationDevided::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(k -> k.getExcutionOrderId(), v -> v));
        //查询收入合同
        Map<Long, IncomeContract> incomeContractMap = CommonUtil.defaultList(incomeContractMapper.selectList(Wrappers.lambdaQuery(IncomeContract.class)
                .in(IncomeContract::getId, incomeContractIds))).stream().collect(Collectors.toMap(k -> k.getId(), v -> v));
        List<RelatedExcutionOrderOutputDTO> outputList = new ArrayList<>();
        for (RelatedExcutionOrderInputDTO inputDTO : inputList) {
            StringBuffer failedReason = new StringBuffer();
            if (StringUtils.isBlank(inputDTO.getExcuteCode())) {
                failedReason.append("执行单号必填！");
            } else if (!excutionOrderMap.containsKey(inputDTO.getExcuteCode())) {
                failedReason.append("执行单编号错误！");
            } else {
                ContractExcutionOrder contractExcutionOrder = excutionOrderMap.get(inputDTO.getExcuteCode());
                inputDTO.setExcuteId(contractExcutionOrder.getId());
                if (!starMonthlySettlement.getStarId().equals(contractExcutionOrder.getStarId())) {
                    failedReason.append("执行单的红人跟月度结算单的红人不一致！");
                }
                if (!ExcutionApprovalStatusEnum.isPassed(contractExcutionOrder.getApprovalStatus())) {
                    failedReason.append("执行单单据状态须是【待打款】！");
                }
                if (repeatedExcuteCodes.contains(inputDTO.getExcuteCode())) {
                    failedReason.append("执行单号重复，请检查后重试！");
                }
                if (existedExcutionOrderIds.contains(contractExcutionOrder.getId())) {
                    failedReason.append("执行单已存在，请勿重复添加！");
                }
                if (relatedExcutionOrderIds.contains(contractExcutionOrder.getId())) {
                    failedReason.append("执行单已关联结算单，导入失败！");
                }
                CalculationDevided calculationDevided = calculationDevidedMap.get(contractExcutionOrder.getId());
                if (Objects.nonNull(calculationDevided)) {
                    inputDTO.setFinanceDevidedAmount(calculationDevided.getFinanceDevidedAmount());
                    inputDTO.setSettlementForm(calculationDevided.getSettlementForm());
                    inputDTO.setContractingId(null);
                    if (!SettlementMethodEnum.BATCH_REMITTANCE.getCode().equals(calculationDevided.getSettlementMethod())) {
                        failedReason.append("请添加结算方式为【批量打款】的执行单！");
                    }
                }
                if (incomeContractMap.containsKey(contractExcutionOrder.getIncomeContractId())) {
                    inputDTO.setContractingId(incomeContractMap.get(contractExcutionOrder.getIncomeContractId()).getContractingId());
                }
            }
            RelatedExcutionOrderOutputDTO outputDTO = new RelatedExcutionOrderOutputDTO();
            BeanUtils.copyProperties(inputDTO, outputDTO);
            outputDTO.setFailedReason(failedReason.toString());
            outputList.add(outputDTO);
        }
        return outputList;
    }

    /**
     * 奇葩需求
     *
     * @param inputList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String importAccruedTax(List<AccruedTaxInputDTO> inputList) {
        inputList = CommonUtil.defaultList(inputList).stream().filter(t -> StringUtils.isNotBlank(t.getSubSettlementCode())).collect(Collectors.toList());
        BusinessAssert.notEmpty(inputList, McnErrorCode.IMPORT_CONTENT_EMPTY);
        List<String> subSettlementCodes = inputList.stream().map(AccruedTaxInputDTO::getSubSettlementCode).distinct().collect(Collectors.toList());
        //筛出有重复的子结算单
        List<String> repeatedSubSettlementCodes = inputList.stream().collect(Collectors.groupingBy(AccruedTaxInputDTO::getSubSettlementCode, Collectors.counting()))
                .entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey()).collect(Collectors.toList());
        //查询子结算单
        List<StarMonthlySettlementSub> subSettlementList = CommonUtil.defaultList(settlementSubMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .in(StarMonthlySettlementSub::getSubSettlementCode, subSettlementCodes).eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO)));
        List<AccruedTaxOutputDTO> outputList = verifyImportAccruedTax(inputList, repeatedSubSettlementCodes, subSettlementList);
        List<AccruedTaxOutputDTO> errorList = outputList.stream().filter(data -> StringUtils.isNotBlank(data.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(errorList)) {
            String fileId = ImportExcelEnum.SETTLEMENT_ACCRUED_TAX.getFileId();
            stringRedisTemplate.opsForValue().set(McnConstant.CACHE_PRIFIX + fileId, JSONObject.toJSONString(outputList), 30, TimeUnit.DAYS);
            return fileId;
        } else {
            Map<Long, ApprovalOperationDTO> approvalMap = new HashMap<>(16);
            Map<Long, List<StarMonthlySettlementTaxDTO.TaxInfo>> acccruedTaxMap = new HashMap<>(16);
            for (AccruedTaxOutputDTO ouputDTO : outputList) {
                if (Objects.isNull(ouputDTO.getApprovalId())) {
                    continue;
                }
                if (!approvalMap.containsKey(ouputDTO.getApprovalId())) {
                    ApprovalOperationDTO approvalOperationDTO = new ApprovalOperationDTO();
                    approvalOperationDTO.setApprovalId(ouputDTO.getApprovalId());
                    approvalOperationDTO.setUserId(UserVoContextHolder.getUserId());
                    approvalOperationDTO.setUserName(UserVoContextHolder.getUserName());
                    approvalOperationDTO.setApprovalFlag(true);
                    approvalMap.put(ouputDTO.getApprovalId(), approvalOperationDTO);
                }
                if (!acccruedTaxMap.containsKey(ouputDTO.getSettlementId())) {
                    acccruedTaxMap.put(ouputDTO.getSettlementId(), new ArrayList<>());
                }
                StarMonthlySettlementTaxDTO.TaxInfo taxInfo = new StarMonthlySettlementTaxDTO.TaxInfo();
                taxInfo.setSubSettlementId(ouputDTO.getSubSettlementId());
                taxInfo.setTaxableAmount(ouputDTO.getTaxableAmount());
                acccruedTaxMap.get(ouputDTO.getSettlementId()).add(taxInfo);
            }
            if (MapUtils.isNotEmpty(approvalMap)) {
                for (Map.Entry<Long, List<StarMonthlySettlementTaxDTO.TaxInfo>> entry : acccruedTaxMap.entrySet()) {
                    StarMonthlySettlementTaxDTO dto = new StarMonthlySettlementTaxDTO();
                    dto.setSettlementId(entry.getKey());
                    dto.setTaxInfoList(entry.getValue());
                    DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT.generateKey(dto.getSettlementId()),
                            () -> this.accruedTax(dto));
                }
                List<ApprovalOperationDTO> approvalList = approvalMap.entrySet().stream().map(e -> e.getValue()).collect(Collectors.toList());
                List<ApprovalOperationVO> approvalResultList = processClient.approvalChange(approvalList).getObj();
                String errorMessage = approvalResultList.stream().filter(d -> !d.isSuccess()).map(ApprovalOperationVO::getMessage).findFirst().orElse("");
                if (StringUtils.isNotBlank(errorMessage)) {
                    throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "审批流提示：" + errorMessage);
                }
            }
        }
        return null;
    }

    /**
     * 校验导入批量计税审批
     *
     * @param inputList
     * @param repeatedSubSettlementCodes
     * @param subSettlementList
     * @return
     */
    private List<AccruedTaxOutputDTO> verifyImportAccruedTax(List<AccruedTaxInputDTO> inputList, List<String> repeatedSubSettlementCodes, List<StarMonthlySettlementSub> subSettlementList) {
        //汇总Excel各结算单填写的子结算单数
        List<Long> subSettlementIds = CommonUtil.defaultList(subSettlementList.stream().map(StarMonthlySettlementSub::getId).collect(Collectors.toList()), -1L);
        List<AccruedTaxSummaryExcel> summaryExcelList = CommonUtil.defaultList(settlementSubMapper.summaryExcel(subSettlementIds));
        Map<Long, Boolean> existedAllSubMap = summaryExcelList.stream().collect(Collectors.toMap(k -> k.getSettlementId(), v -> v.getExcelSubNum().longValue() == v.getDbSubNum().longValue()));
        //查询结算单
        Map<String, StarMonthlySettlementSub> subSettlementMap = subSettlementList.stream().collect(Collectors.toMap(k -> k.getSubSettlementCode(), v -> v));
        List<Long> settlementIds = CommonUtil.defaultList(subSettlementList.stream().map(StarMonthlySettlementSub::getSettlementId).distinct().collect(Collectors.toList()), -1L);
        Map<Long, StarMonthlySettlement> settlementMap = CommonUtil.defaultList(settlementMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlement.class)
                .in(StarMonthlySettlement::getId, settlementIds).eq(StarMonthlySettlement::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(k -> k.getId(), v -> v));
        Map<Long, ApprovalNodeVO> nodeMap = approvalFlowService.getCurrentApprovalNodes(settlementIds, Arrays.asList(ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId()));
        List<AccruedTaxOutputDTO> outputList = new ArrayList<>();
        for (AccruedTaxInputDTO inputDTO : inputList) {
            StringBuffer failedReason = new StringBuffer();
            if (StringUtils.isBlank(inputDTO.getSubSettlementCode()) || Objects.isNull(inputDTO.getTaxableAmount())) {
                failedReason.append("子结算单号、应扣税额（元）都是必填！");
            } else {
                if (repeatedSubSettlementCodes.contains(inputDTO.getSubSettlementCode())) {
                    failedReason.append("子结算单号重复！");
                }
                StarMonthlySettlementSub subSettlement = subSettlementMap.get(inputDTO.getSubSettlementCode());
                if (Objects.isNull(subSettlement)) {
                    failedReason.append("找不到子结算单号！");
                } else {
                    StarMonthlySettlement starMonthlySettlement = settlementMap.get(subSettlement.getSettlementId());
                    if (Objects.isNull(starMonthlySettlement)) {
                        failedReason.append("找不到结算单号！");
                    } else {
                        if (!ObjectUtils.defaultIfNull(existedAllSubMap.get(starMonthlySettlement.getId()), Boolean.FALSE).booleanValue()) {
                            failedReason.append(String.format("【%s】结算单的子结算单不全，请检查后补齐！", starMonthlySettlement.getSettlementCode()));
                        }
                        if (!StarMonthlySettlementStatusEnum.isApproval(starMonthlySettlement.getApprovalStatus())) {
                            failedReason.append("子结算单对应结算单据状态须是【审批中】！");
                        } else {
                            inputDTO.setSettlementId(starMonthlySettlement.getId());
                            inputDTO.setSubSettlementId(subSettlement.getId());
                            ApprovalNodeVO approvalNodeVO = nodeMap.get(starMonthlySettlement.getId());
                            if (Objects.isNull(approvalNodeVO) || !"HR计税".equals(approvalNodeVO.getNodeName())) {
                                failedReason.append("子结算单对应结算审批节点须是【HR计税】！");
                            } else {
                                inputDTO.setApprovalId(approvalNodeVO.getApprovalId());
                                BigDecimal taxableAmount = inputDTO.getTaxableAmount();
                                if (taxableAmount.compareTo(BigDecimal.ZERO) == -1 || taxableAmount.scale() > 2) {
                                    failedReason.append("请录入数字最多包含两位小数的应扣税额（元）！");
                                }
                                if (taxableAmount.compareTo(subSettlement.getOnlineInvoiceAmount()) > 0) {
                                    failedReason.append("应扣税额（元）不能大于线上结算发票金额（元）！");
                                }
                            }
                        }
                    }
                }
            }
            AccruedTaxOutputDTO outputDTO = new AccruedTaxOutputDTO();
            BeanUtils.copyProperties(inputDTO, outputDTO);
            outputDTO.setFailedReason(failedReason.toString());
            outputList.add(outputDTO);
        }
        return outputList;
    }

    @Override
    public void excelDownload(HttpServletResponse response, String fileId) {
        ImportExcelEnum excelEnum = ImportExcelEnum.toEnum(fileId);
        BusinessAssert.notNull(excelEnum, McnErrorCode.EXPORT_FILE_ID_ILLEGAL);
        // 根据FileId判断导出类型
        String excelContent = CommonUtil.defaultIfEmpty(stringRedisTemplate.opsForValue().get(McnConstant.CACHE_PRIFIX + fileId));
        BusinessAssert.notBlank(excelContent, McnErrorCode.EXPORT_HAS_NO_DATA);
        try {
            String title = null;
            switch (excelEnum) {
                case SETTLEMENT_EXCUTION_ORDER:
                    title = "导入执行单-失败原因";
                    ExcelUtils.exportExcel(JSONObject.parseObject(excelContent, new TypeReference<List<RelatedExcutionOrderOutputDTO>>() {
                            }),
                            title, RelatedExcutionOrderOutputDTO.class, title + ".xlsx", response);
                    break;
                case SETTLEMENT_ACCRUED_TAX:
                    title = "HR计税批量审批-失败原因";
                    ExcelUtils.exportExcel(JSONObject.parseObject(excelContent, new TypeReference<List<AccruedTaxOutputDTO>>() {
                            }),
                            title, AccruedTaxOutputDTO.class, title + ".xlsx", response);

                    break;
                default:
                    break;
            }
            if (Objects.nonNull(excelEnum)) {
                stringRedisTemplate.delete(McnConstant.CACHE_PRIFIX + fileId);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BigDecimal accruedTax(StarMonthlySettlementTaxDTO dto) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(dto.getSettlementId(), true);
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isApproval(starMonthlySettlement.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "非审批中，不允许操作！");
        List<Long> subIds = dto.getTaxInfoList().stream().map(StarMonthlySettlementTaxDTO.TaxInfo::getSubSettlementId).distinct().collect(Collectors.toList());
        Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(subIds)).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
        dto.getTaxInfoList().forEach(info -> {
            ValidatorUtil.validate(info, Modify.class);
            BigDecimal taxableAmount = info.getTaxableAmount();
            BusinessAssert.isTrue(taxableAmount.compareTo(BigDecimal.ZERO) >= 0 && taxableAmount.scale() <= 2, McnErrorCode.VERIFY_AMOUNT_ERROR, "请正确输入应扣税额（>=0 且 小数位<=2）");
            StarMonthlySettlementSub starMonthlySettlementSub = this.getSettlementSub(info.getSubSettlementId(), true);
            BusinessAssert.isTrue(starMonthlySettlementSub.getOnlineInvoiceAmount().compareTo(taxableAmount) >= 0, McnErrorCode.VERIFY_AMOUNT_ERROR, "应扣税额不能大于线上结算发票金额");
            settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                    .set(StarMonthlySettlementSub::getTaxableAmount, info.getTaxableAmount())
                    .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                    .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                    .eq(StarMonthlySettlementSub::getSettlementId, starMonthlySettlement.getId())
                    .eq(StarMonthlySettlementSub::getId, starMonthlySettlementSub.getId()));
            //计算均摊个税
            List<StarMonthlySettlementDetail> detailList = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                    .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId())
                    .eq(StarMonthlySettlementDetail::getSubSettlementId, starMonthlySettlementSub.getId())
                    .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                    .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO));
            ShareTaxAmountContext ruleContext = new ShareTaxAmountContext();
            ruleContext.setPretaxAmount(starMonthlySettlementSub.getPretaxAmount());
            ruleContext.setTaxableAmount(info.getTaxableAmount());
            ruleContext.setDevidedMap(detailList.stream().collect(Collectors.toMap(k -> k.getId(), v -> v.getFinanceDevidedAmount())));
            Map<Long, BigDecimal> resultMap = ComputableRuleEngine.fire(ShareTaxAmountRule.class, ruleContext);
            detailList.forEach(detail -> {
                StarMonthlySettlementDetail updateDetail = new StarMonthlySettlementDetail();
                updateDetail.setId(detail.getId());
                updateDetail.setShareTaxAmount(resultMap.get(detail.getId()));
                updateDetail.setAftertaxShareAmount(detail.getFinanceDevidedAmount().subtract(ObjectUtils.defaultIfNull(updateDetail.getShareTaxAmount(), BigDecimal.ZERO)));
                settlementDetailMapper.updateById(updateDetail);
            });
        });
        if(MapUtils.isNotEmpty(oldSubMap)) {
            this.sendBatchLog(starMonthlySettlement.getId(), oldSubMap);
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean inputInvoice(StarMonthlySettlementSubmiterDTO dto) {
        StarMonthlySettlement entity = this.getSettlement(dto.getSettlementId(), true);
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isApproval(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "非审批中，不允许操作！");
        dto.getInvoiceInfoList().forEach(info -> {
            ValidatorUtil.validate(info, Modify.class);
            StarMonthlySettlementSub starMonthlySettlementSub = this.getSettlementSub(info.getSubSettlementId(), true);
            settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                    .set(StarMonthlySettlementSub::getInvoiceNo, info.getInvoiceNo())
                    .set(StarMonthlySettlementSub::getInvoiceDate, info.getInvoiceDate())
                    .set(StarMonthlySettlementSub::getInvoiceScreenshot, info.getInvoiceScreenshot())
                    .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                    .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                    .eq(StarMonthlySettlementSub::getSettlementId, entity.getId())
                    .eq(StarMonthlySettlementSub::getId, starMonthlySettlementSub.getId()));
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(entity.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlementSub, settlementSubMapper.selectById(starMonthlySettlementSub.getId()))
                    .build());
        });
        return true;
    }

    @Override
    public boolean financeExamine(StarMonthlySettlementFinanceExamineDTO dto) {
        ValidatorUtil.validate(dto, Modify.class);
        StarMonthlySettlement entity = this.getSettlement(dto.getSettlementId(), true);
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isApproval(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "非审批中，不允许操作！");
        dto.getFinancePaidInfoList().forEach(info -> {
            StarMonthlySettlementSub starMonthlySettlementSub = this.getSettlementSub(info.getSubSettlementId(), true);
            settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                    .set(StarMonthlySettlementSub::getOnlineInvoiceAmount, info.getOnlineInvoiceAmount())
                    .set(StarMonthlySettlementSub::getFinanceConfirmedDevidedAmount, info.getFinanceConfirmedDevidedAmount())
                    .set(StarMonthlySettlementSub::getFinanceAttachment, info.getFinanceAttachment())
                    .set(StarMonthlySettlementSub::getRemark, info.getRemark())
                    .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                    .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                    .eq(StarMonthlySettlementSub::getSettlementId, entity.getId())
                    .eq(StarMonthlySettlementSub::getId, starMonthlySettlementSub.getId()));
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(entity.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlementSub, settlementSubMapper.selectById(starMonthlySettlementSub.getId()))
                    .build());
        });
        return true;
    }

    @SuppressWarnings("AlibabaAvoidComplexCondition")
    private void validateStatus(StarMonthlySettlement starMonthlySettlement, Integer status) {
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.UN_COMMIT.getCode() &&
                (status != StarMonthlySettlementStatusEnum.APPROVAL.getCode() && status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_UN_COMMIT_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.APPROVAL.getCode() &&
                (status != StarMonthlySettlementStatusEnum.CANCEL.getCode() && status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_APPROVAL_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.UN_PAYBACK.getCode() &&
                (status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_UN_PAYBACK_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.REJECTED.getCode() &&
                (status != StarMonthlySettlementStatusEnum.APPROVAL.getCode() && status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_REJECTED_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.CANCEL.getCode() &&
                (status != StarMonthlySettlementStatusEnum.APPROVAL.getCode() && status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_CANCEL_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.PART_PAYBACK.getCode() &&
                (status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_PART_PAYBACK_ERROR);
        }
        if (starMonthlySettlement.getApprovalStatus() == StarMonthlySettlementStatusEnum.ALL_PAYBACK.getCode() &&
                (status != StarMonthlySettlementStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_MONTHLY_SETTLEMENT_ALL_PAYBACK_ERROR);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean changeStatus(Long id, Integer approvalStatus) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(id, true);
        validateStatus(starMonthlySettlement, approvalStatus);
        BusinessAssert.isFalse(StarMonthlySettlementStatusEnum.isInvalid(starMonthlySettlement.getApprovalStatus()),
                McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "该结算单已作废，不允许操作！");
        if (StarMonthlySettlementStatusEnum.isApproval(approvalStatus)) {
            //详情页提起审批-校验参数
            StarMonthlySettlementSaveDTO saveDTO = new StarMonthlySettlementSaveDTO();
            BeanUtils.copyProperties(starMonthlySettlement, saveDTO);
            ValidatorUtil.validate(saveDTO, Modify.class);
            BusinessAssert.isTrue(settlementDetailMapper.selectCount(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                            .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId()).eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)) > 0
                    , McnErrorCode.PARAM_ERROR, "未关联执行单-不允许提交审批！");
            //结算单-拆单
            this.splitSettlement(starMonthlySettlement);
        } else {
            if (StarMonthlySettlementStatusEnum.isInvalid(approvalStatus)) {
                if (StarMonthlySettlementStatusEnum.anyMatch(starMonthlySettlement.getApprovalStatus(),
                        StarMonthlySettlementStatusEnum.UN_PAYBACK, StarMonthlySettlementStatusEnum.PART_PAYBACK, StarMonthlySettlementStatusEnum.ALL_PAYBACK)) {
                    //判断该单据是否能在财务模块费用表查询到非删除状态的费用
                    Integer relatedCount = financeClient.getInvalid(starMonthlySettlement.getSettlementCode(), null, null).getObj();
                    BusinessAssert.isTrue(relatedCount <= 0, McnErrorCode.INVALID_FAILED);
                }
                //注意顺序
                //1、全部打款后再作废结算单-则回滚执行单状态
                this.updateExcutionOrderStatusIfNecessary(starMonthlySettlement, null, starMonthlySettlement.getApprovalStatus(), true);
                //2、释放绑定的执行单
                settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                        .set(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ONE)
                        .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                        .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                        .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId()));

            } else if (StarMonthlySettlementStatusEnum.isCancel(approvalStatus)) {
                BusinessAssert.isFalse(StarMonthlySettlementStatusEnum.anyMatch(starMonthlySettlement.getApprovalStatus(),
                        StarMonthlySettlementStatusEnum.UN_PAYBACK, StarMonthlySettlementStatusEnum.PART_PAYBACK, StarMonthlySettlementStatusEnum.ALL_PAYBACK)
                        , McnErrorCode.PARAM_ERROR, "已审批通过-不允许撤回！");
                //更新子结算单-打款金额
                this.updateFinanceConfirmedDevidedAmountDetail(id, true);
                //删除之前的拆单信息
                this.deletePreviousSplit(starMonthlySettlement);
            }
        }
        boolean isCancel = StarMonthlySettlementStatusEnum.isCancel(approvalStatus);
        boolean result = settlementMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlement.class)
                .set(StarMonthlySettlement::getApprovalStatus, approvalStatus)
                .set(isCancel, StarMonthlySettlement::getOnlinePaidStatus, PaidStatusEnum.UN_PAYBACK.getCode())
                .set(isCancel, StarMonthlySettlement::getOfflinePaidStatus, PaidStatusEnum.UN_PAYBACK.getCode())
                .set(StarMonthlySettlement::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlement::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlement::getUpdateDate, new Date())
                .eq(StarMonthlySettlement::getId, starMonthlySettlement.getId()));
        if (result) {
            //如果红人月度结算单撤回或作废，则撤回已提起的审批流程
            if (StarMonthlySettlementStatusEnum.anyMatch(approvalStatus, StarMonthlySettlementStatusEnum.CANCEL, StarMonthlySettlementStatusEnum.INVALID)) {
                approvalFlowService.revokeProcess(starMonthlySettlement.getId(), ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId());
            } else if (StarMonthlySettlementStatusEnum.isApproval(approvalStatus)) {
                approvalFlowService.startProcess(starMonthlySettlement.getId(), starMonthlySettlement.getSettlementCode(), ApprovalEnum.STAR_MONTHLY_SETTLEMENT, JSON.toJSONString(starMonthlySettlement));
                stringRedisTemplate.opsForValue().set(APPROVAL_KEY + starMonthlySettlement.getSettlementCode(), JSONObject.toJSONString(UserVoContextHolder.getUserVo()), 100, TimeUnit.DAYS);
            }
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlement, settlementMapper.selectById(starMonthlySettlement.getId()))
                    .build());
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updatePayback(ChargeClearCallback dto, StarMonthlySettlementSub starMonthlySettlementSub) {
        BigDecimal paybackAmount = dto.getPaybackAmount();
        MessageTopicEnum topicEnum = MessageTopicEnum.PAYBACK_CALLBACK_HRJS;
        StarMonthlySettlement starMonthlySettlement = settlementMapper.selectById(starMonthlySettlementSub.getSettlementId());
        BusinessAssert.notNull(starMonthlySettlement, McnErrorCode.DATA_NOT_FOUND, String.format("【%s】查询不到该结算单", topicEnum.getDesc()));
        //是否冲销
        boolean isChargeAgainst = paybackAmount.compareTo(BigDecimal.ZERO) == -1;
        if(!isChargeAgainst) {
            BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.anyMatch(starMonthlySettlement.getApprovalStatus(),
                    StarMonthlySettlementStatusEnum.UN_PAYBACK, StarMonthlySettlementStatusEnum.PART_PAYBACK),
                    McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "结算单状态-非待打款或部分打款");
        }
        Date now = new Date();
        //更新收入合同已开票金额
        StarMonthlySettlement updateEntity = new StarMonthlySettlement();
        updateEntity.setPaybackAmount(paybackAmount.add(ObjectUtils.defaultIfNull(starMonthlySettlement.getPaybackAmount(), BigDecimal.ZERO)));
        //查询子结算单-核销回款标记
        updateEntity.setPaybackDate(now);
        updateEntity.setApprovalStatus(StarMonthlySettlementStatusEnum.PART_PAYBACK.getCode());
        dto.setTotalPaybackAmount(updateEntity.getPaybackAmount());
        String messageBody = JSONObject.toJSONString(dto);
        String messageKey = StringUtils.joinWith(isChargeAgainst ? "-" : "+", dto.getClearNo(), starMonthlySettlement.getSettlementCode());
        String signature = CommonUtil.hmacMd5Hex(messageBody);
        MessageInfo messageInfo = MessageInfo.builder().messageTopic(topicEnum.name()).messageKey(messageKey)
                .tenantId(starMonthlySettlement.getTenantId())
                .messageBody(messageBody).signature(signature).status(MessageStatusEnum.SUCCESS.getType()).build();
        if (!messageInfoService.addMessageInfo(messageInfo)) {
            MessageInfo entity = messageInfoService.selectOne(Wrappers.lambdaQuery(MessageInfo.class)
                    .eq(MessageInfo::getMessageTopic, topicEnum.name())
                    .eq(MessageInfo::getMessageKey, messageKey)
                    .eq(MessageInfo::getTenantId, starMonthlySettlement.getTenantId())
                    .eq(MessageInfo::getIsDelete, Boolean.FALSE)
            );
            BusinessAssert.notNull(entity, McnErrorCode.BUSINESS_ERROR, String.format("【%s】数据幂等处理异常", topicEnum.getDesc()));
            //判断消息内容签名，如果相等，重复回调
            if (signature.equals(entity.getSignature())) {
                //也可以进一步比较金额
                return true;
            }
            ChargeClearCallback payload = JSONObject.parseObject(entity.getMessageBody(), ChargeClearCallback.class);
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(),
                    String.format("【%s】重复请求！上次回调：核销单号=%s，金额=%s，子结算单号=%s", topicEnum.getDesc(), payload.getClearNo(), payload.getPaybackAmount(), payload.getSourceBillCode()));
        }
        updateEntity.setId(starMonthlySettlement.getId());
        updateEntity.setUpdateBy(dto.getOperatorId());
        updateEntity.setUpdateName(dto.getOperatorName());
        updateEntity.setUpdateDate(now);
        boolean result = settlementMapper.updateById(updateEntity) > 0;
        if (result) {
            //更新子结算单
            StarMonthlySettlementSub updateSubSettlement = new StarMonthlySettlementSub();
            updateSubSettlement.setId(starMonthlySettlementSub.getId());
            updateSubSettlement.setIsClear(NumberCst.ONE);
            updateSubSettlement.setUpdateBy(dto.getOperatorId());
            updateSubSettlement.setUpdateName(dto.getOperatorName());
            updateSubSettlement.setPaidDate(dto.getPaybackDate());
            updateSubSettlement.setUpdateDate(now);
            settlementSubMapper.updateById(updateSubSettlement);
            //红人月度结算单已打款后，关联待打款的执行单-置为已打款
            starMonthlySettlement.setUpdateBy(dto.getOperatorId());
            starMonthlySettlement.setUpdateName(dto.getOperatorName());
            starMonthlySettlement.setUpdateDate(now);
            StarMonthlySettlementSub newStarMonthlySettlementSub =  settlementSubMapper.selectById(starMonthlySettlementSub.getId());
            this.updateExcutionOrderStatusIfNecessary(starMonthlySettlement, newStarMonthlySettlementSub, updateEntity.getApprovalStatus(), false);
            //判断是否全部回款，如果是则更新
            this.updatePaybackStatus(starMonthlySettlement, true);
            //操作日志-子结算单
            EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(starMonthlySettlementSub, newStarMonthlySettlementSub)
                    .build());
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApprovalOperationVO changeApproval(ChangeApprovalDTO dto, Long billId) {
        StarMonthlySettlement entity = this.getSettlement(billId, true);
        BusinessAssert.isFalse(StarMonthlySettlementStatusEnum.isInvalid(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "单据已作废，不允许操作！");
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isApproval(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "单据非审批中，不允许操作！");
        ApprovalOperationVO approvalOperationVO;
        if (!dto.getApprovalFlag().booleanValue()) {
            //更新子结算单-打款金额
            this.updateFinanceConfirmedDevidedAmountDetail(entity.getId(), true);
            approvalOperationVO = approvalFlowService.approvalChange(dto.getApprovalId(), JSON.toJSONString(dto.getParamMap()), Boolean.FALSE, dto.getRemark());
        } else {
            if (CommonUtil.containsKeys(dto.getParamMap(), "financePaidInfoList")) {
                StarAccountInfo starAccountInfo = starAccountInfoService.getById(entity.getStarAccountId());
                BusinessAssert.notNull(starAccountInfo, McnErrorCode.BUSINESS_ERROR, "查询不到该红人收款账号信息！");
                dto.getParamMap().put("studioPayment", StudioPaymentEnum.getDesc(starAccountInfo.getStudioPayment()));
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                StarMonthlySettlementFinanceExamineDTO financeExamineDTO = JSON.parseObject(approvalParam, StarMonthlySettlementFinanceExamineDTO.class);
                financeExamineDTO.setApprovalId(dto.getApprovalId());
                financeExamineDTO.setSettlementId(entity.getId());
                ValidatorUtil.validate(financeExamineDTO);
                financeExamineDTO.getFinancePaidInfoList().forEach(e -> {
                    BusinessAssert.isTrue(e.getFinanceConfirmedDevidedAmount().compareTo(e.getOnlineInvoiceAmount()) >= 0, "线上结算发票金额不能大于财务确认可分成金额！");
                });
                List<Long> subIds = financeExamineDTO.getFinancePaidInfoList().stream().map(StarMonthlySettlementFinanceExamineDTO.FinancePaidInfo::getSubSettlementId).distinct().collect(Collectors.toList());
                Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(subIds)).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
                for(StarMonthlySettlementFinanceExamineDTO.FinancePaidInfo financePaidInfo : financeExamineDTO.getFinancePaidInfoList()) {
                    BigDecimal offlineInvoiceAmount = ObjectUtils.defaultIfNull(financePaidInfo.getFinanceConfirmedDevidedAmount(), BigDecimal.ZERO)
                            .subtract(ObjectUtils.defaultIfNull(financePaidInfo.getOnlineInvoiceAmount(), BigDecimal.ZERO));
                    settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                            .set(StarMonthlySettlementSub::getFinanceConfirmedDevidedAmount, financePaidInfo.getFinanceConfirmedDevidedAmount())
                            .set(StarMonthlySettlementSub::getOnlineInvoiceAmount, financePaidInfo.getOnlineInvoiceAmount())
                            .set(StarMonthlySettlementSub::getOfflineInvoiceAmount, offlineInvoiceAmount)
                            .set(StarMonthlySettlementSub::getFinanceAttachment, financePaidInfo.getFinanceAttachment())
                            .set(StarMonthlySettlementSub::getRemark, financePaidInfo.getRemark())
                            .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                            .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                            .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                            .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                            .eq(StarMonthlySettlementSub::getId, financePaidInfo.getSubSettlementId())
                            .eq(StarMonthlySettlementSub::getSettlementId, entity.getId()));
                }
                approvalOperationVO = approvalFlowService.approvalChange(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
                if (approvalOperationVO.isSuccess() && MapUtils.isNotEmpty(oldSubMap)) {
                    this.sendBatchLog(entity.getId(), oldSubMap);
                }
            } else if (CommonUtil.containsKeys(dto.getParamMap(), "taxInfoList")) {
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                StarMonthlySettlementTaxDTO accruedTaxDTO = JSON.parseObject(approvalParam, StarMonthlySettlementTaxDTO.class);
                accruedTaxDTO.setApprovalId(dto.getApprovalId());
                accruedTaxDTO.setSettlementId(entity.getId());
                ValidatorUtil.validate(accruedTaxDTO);
                List<Long> subIds = accruedTaxDTO.getTaxInfoList().stream().map(StarMonthlySettlementTaxDTO.TaxInfo::getSubSettlementId).distinct().collect(Collectors.toList());
                Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(subIds)).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
                accruedTaxDTO.getTaxInfoList().forEach(e -> {
                    StarMonthlySettlementSub sub = oldSubMap.get(e.getSubSettlementId());
                    if(Objects.nonNull(sub)) {
                        BusinessAssert.isTrue(sub.getOnlineInvoiceAmount().compareTo(e.getTaxableAmount()) >= 0, "应扣税额不能大于线上结算发票金额！");
                    }
                });
                for(StarMonthlySettlementTaxDTO.TaxInfo taxInfo : accruedTaxDTO.getTaxInfoList()) {
                    StarMonthlySettlementSub updateSub = new StarMonthlySettlementSub();
                    updateSub.setId(taxInfo.getSubSettlementId());
                    updateSub.setTaxableAmount(taxInfo.getTaxableAmount());
                    settlementSubMapper.updateById(updateSub);
                }
                approvalOperationVO = approvalFlowService.approvalChange(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
                if (approvalOperationVO.isSuccess() && MapUtils.isNotEmpty(oldSubMap)) {
                    this.sendBatchLog(entity.getId(), oldSubMap);
                }
            } else {
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                approvalOperationVO = approvalFlowService.approvalChange(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
            }
        }
        BusinessAssert.isTrue(approvalOperationVO.isSuccess(), McnErrorCode.FLOW_ERROR, approvalOperationVO.getMessage());
        return approvalOperationVO;
    }

    /**
     * 审批流程并返回下一条
     * @param dto
     * @param billId 单据ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public NextNotifyVo changeApprovalNext(ChangeApprovalDTO dto, Long billId) {
        StarMonthlySettlement entity = this.getSettlement(billId, true);
        BusinessAssert.isFalse(StarMonthlySettlementStatusEnum.isInvalid(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "单据已作废，不允许操作！");
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isApproval(entity.getApprovalStatus()), McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "单据非审批中，不允许操作！");
        NextNotifyVo nextNotifyVo;
        if (!dto.getApprovalFlag().booleanValue()) {
            //更新子结算单-打款金额
            this.updateFinanceConfirmedDevidedAmountDetail(entity.getId(), true);
            nextNotifyVo = approvalFlowService.approvalChangeNext(dto.getApprovalId(), JSON.toJSONString(dto.getParamMap()), Boolean.FALSE, dto.getRemark());
        } else {
            if (CommonUtil.containsKeys(dto.getParamMap(), "financePaidInfoList")) {
                StarAccountInfo starAccountInfo = starAccountInfoService.getById(entity.getStarAccountId());
                BusinessAssert.notNull(starAccountInfo, McnErrorCode.BUSINESS_ERROR, "查询不到该红人收款账号信息！");
                dto.getParamMap().put("studioPayment", StudioPaymentEnum.getDesc(starAccountInfo.getStudioPayment()));
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                StarMonthlySettlementFinanceExamineDTO financeExamineDTO = JSON.parseObject(approvalParam, StarMonthlySettlementFinanceExamineDTO.class);
                financeExamineDTO.setApprovalId(dto.getApprovalId());
                financeExamineDTO.setSettlementId(entity.getId());
                ValidatorUtil.validate(financeExamineDTO);
                financeExamineDTO.getFinancePaidInfoList().forEach(e -> {
                    BusinessAssert.isTrue(e.getFinanceConfirmedDevidedAmount().compareTo(e.getOnlineInvoiceAmount()) >= 0, "线上结算发票金额不能大于财务确认可分成金额！");
                });
                List<Long> subIds = financeExamineDTO.getFinancePaidInfoList().stream().map(StarMonthlySettlementFinanceExamineDTO.FinancePaidInfo::getSubSettlementId).distinct().collect(Collectors.toList());
                Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(subIds)).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
                for(StarMonthlySettlementFinanceExamineDTO.FinancePaidInfo financePaidInfo : financeExamineDTO.getFinancePaidInfoList()) {
                    BigDecimal offlineInvoiceAmount = ObjectUtils.defaultIfNull(financePaidInfo.getFinanceConfirmedDevidedAmount(), BigDecimal.ZERO)
                            .subtract(ObjectUtils.defaultIfNull(financePaidInfo.getOnlineInvoiceAmount(), BigDecimal.ZERO));
                    settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                            .set(StarMonthlySettlementSub::getFinanceConfirmedDevidedAmount, financePaidInfo.getFinanceConfirmedDevidedAmount())
                            .set(StarMonthlySettlementSub::getOnlineInvoiceAmount, financePaidInfo.getOnlineInvoiceAmount())
                            .set(StarMonthlySettlementSub::getOfflineInvoiceAmount, offlineInvoiceAmount)
                            .set(StarMonthlySettlementSub::getFinanceAttachment, financePaidInfo.getFinanceAttachment())
                            .set(StarMonthlySettlementSub::getRemark, financePaidInfo.getRemark())
                            .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                            .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                            .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                            .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                            .eq(StarMonthlySettlementSub::getId, financePaidInfo.getSubSettlementId())
                            .eq(StarMonthlySettlementSub::getSettlementId, entity.getId()));
                }
                nextNotifyVo = approvalFlowService.approvalChangeNext(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
                if (Objects.nonNull(nextNotifyVo) && MapUtils.isNotEmpty(oldSubMap)) {
                    this.sendBatchLog(entity.getId(), oldSubMap);
                }
            } else if (CommonUtil.containsKeys(dto.getParamMap(), "taxInfoList")) {
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                StarMonthlySettlementTaxDTO accruedTaxDTO = JSON.parseObject(approvalParam, StarMonthlySettlementTaxDTO.class);
                accruedTaxDTO.setApprovalId(dto.getApprovalId());
                accruedTaxDTO.setSettlementId(entity.getId());
                ValidatorUtil.validate(accruedTaxDTO);
                List<Long> subIds = accruedTaxDTO.getTaxInfoList().stream().map(StarMonthlySettlementTaxDTO.TaxInfo::getSubSettlementId).distinct().collect(Collectors.toList());
                Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(subIds)).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
                accruedTaxDTO.getTaxInfoList().forEach(e -> {
                    StarMonthlySettlementSub sub = oldSubMap.get(e.getSubSettlementId());
                    if(Objects.nonNull(sub)) {
                        BusinessAssert.isTrue(sub.getOnlineInvoiceAmount().compareTo(e.getTaxableAmount()) >= 0, "应扣税额不能大于线上结算发票金额！");
                    }
                });
                for(StarMonthlySettlementTaxDTO.TaxInfo taxInfo : accruedTaxDTO.getTaxInfoList()) {
                    StarMonthlySettlementSub updateSub = new StarMonthlySettlementSub();
                    updateSub.setId(taxInfo.getSubSettlementId());
                    updateSub.setTaxableAmount(taxInfo.getTaxableAmount());
                    settlementSubMapper.updateById(updateSub);
                }
                nextNotifyVo = approvalFlowService.approvalChangeNext(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
                if (Objects.nonNull(nextNotifyVo) && MapUtils.isNotEmpty(oldSubMap)) {
                    this.sendBatchLog(entity.getId(), oldSubMap);
                }
            } else {
                String approvalParam = JSON.toJSONString(dto.getParamMap());
                nextNotifyVo = approvalFlowService.approvalChangeNext(dto.getApprovalId(), approvalParam, Boolean.TRUE, dto.getRemark());
            }
        }
        return nextNotifyVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void approvalCallback(ApprovalFlowDTO approvalFlowDTO, Boolean status) {
        StarMonthlySettlement entity = this.getSettlement(approvalFlowDTO.getSrcId(), true);
        approvalFlowDTO.setSrcCode(entity.getSettlementCode());
        approvalFlowDTO.addSubmitInfoIfNull(entity);
        if (Objects.isNull(status)) {
            //审批流配置-接入待办
            return;
        }
        if (StarMonthlySettlementStatusEnum.anyMatch(entity.getApprovalStatus(), StarMonthlySettlementStatusEnum.UN_PAYBACK, StarMonthlySettlementStatusEnum.REJECTED)) {
            log.error("红人月度结算单-流程审批结束重复回调，不做处理！approvalId={}", approvalFlowDTO.getApprovalId());
            return;
        }
        //流程审批结束
        Integer approvalStatus = status.booleanValue() ? StarMonthlySettlementStatusEnum.UN_PAYBACK.getCode() : StarMonthlySettlementStatusEnum.REJECTED.getCode();
        LambdaUpdateWrapper<StarMonthlySettlement> lambdaUpdateWrapper = Wrappers.lambdaUpdate(StarMonthlySettlement.class);
        //更新线上、线下打款状态
        if (StarMonthlySettlementStatusEnum.unPackback(approvalStatus)) {
            Map<Integer, Long> formCountMap = CommonUtil.defaultList(settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                    .select(StarMonthlySettlementDetail::getId, StarMonthlySettlementDetail::getSettlementForm)
                    .eq(StarMonthlySettlementDetail::getSettlementId, entity.getId())
                    .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                    .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)))
                    .stream().collect(Collectors.groupingBy(StarMonthlySettlementDetail::getSettlementForm, Collectors.counting()));
            if(!formCountMap.containsKey(NumberCst.ZERO)) {
                lambdaUpdateWrapper.set(StarMonthlySettlement::getOnlinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode());
            }
            if(!formCountMap.containsKey(NumberCst.ONE)) {
                lambdaUpdateWrapper.set(StarMonthlySettlement::getOfflinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode());
            }
        } else {
            lambdaUpdateWrapper.set(StarMonthlySettlement::getOnlinePaidStatus, PaidStatusEnum.UN_PAYBACK.getCode());
            lambdaUpdateWrapper.set(StarMonthlySettlement::getOfflinePaidStatus, PaidStatusEnum.UN_PAYBACK.getCode());
        }
        lambdaUpdateWrapper.set(StarMonthlySettlement::getApprovalStatus, approvalStatus);
        boolean isRejected = StarMonthlySettlementStatusEnum.REJECTED.getCode() == approvalStatus.intValue();
        BusinessAssert.isTrue(DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT.generateKey(entity.getId()), () -> {
            boolean result = settlementMapper.updateByNoStrategy(lambdaUpdateWrapper
                    .set(StarMonthlySettlement::getUpdateBy, approvalFlowDTO.getUserId())
                    .set(StarMonthlySettlement::getUpdateName, approvalFlowDTO.getUserName())
                    .set(StarMonthlySettlement::getUpdateDate, new Date())
                    .eq(StarMonthlySettlement::getId, entity.getId()));
            if (result) {
                //如果审批拒绝-删除之前的拆单信息
                if (isRejected) {
                    log.info("红人月度结算单-审批拒绝，则删除之前拆单信息");
                    this.deletePreviousSplit(entity);
                } else {
                    //更新子结算单-打款金额
                    this.updateFinanceConfirmedDevidedAmountDetail(entity.getId(), false);
                    //审批通过后，需要将月度结算单里面所有执行单的【结算形式】，同步更新至【执行单】的结算形式字段里面
                    this.updateSettlementFormOfExcutionOrder(entity);
                }
                //操作日志
                EventPublisher.post(OperateLogEvent.builder().businessId(entity.getId())
                        .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                        .compare(entity, settlementMapper.selectById(entity.getId()))
                        .build());
            }
            return result;
        }), McnErrorCode.FLOW_CALLBACK_HANDLE_EXCEPTION);
        // 待回款(审批通过) => 生成费用推送财务系统
        if (StarMonthlySettlementStatusEnum.unPackback(approvalStatus)) {
            messageProducer.sendRecordToMq(entity.getId());
        } else {
            //如果全部回款-关联待打款的执行单-置为已打款
            this.updateExcutionOrderStatusIfNecessary(entity, null, approvalStatus, false);
        }
        //发送流程结束通知
        approvalFlowService.sendNotify(approvalFlowDTO, entity.getId(), entity.getSettlementCode(),
                ApprovalEnum.STAR_MONTHLY_SETTLEMENT, status, entity.getCreateBy(), entity.getCreateName());
    }

    @Override
    public StarMonthlySettlement getSettlement(Long settlementId, boolean verifyExist) {
        StarMonthlySettlement entity = settlementMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlement.class)
                .eq(StarMonthlySettlement::getId, settlementId).eq(StarMonthlySettlement::getIsDelete, NumberCst.ZERO));
        if (verifyExist) {
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "该结算单不存在");
        }
        return entity;
    }

    @Override
    public StarMonthlySettlementSub getSettlementSub(Long subSettlementId, boolean verifyExist) {
        StarMonthlySettlementSub entity = settlementSubMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .eq(StarMonthlySettlementSub::getId, subSettlementId).eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO));
        if (verifyExist) {
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "该子结算单不存在");
        }
        return entity;
    }


    /**
     * ############ 何旭东 ############
     */

    @Override
    public StarMonthlySettlementPaySummaryVO paySummary(Long id) {
        StarMonthlySettlementPaySummaryVO summaryVO = settlementDetailMapper.getPaySummary(id);
        summaryVO.setAfterTaxTotalAmount(summaryVO.getPretaxTotalAmount().subtract(summaryVO.getTaxableTotalAmount()));
        return summaryVO;
    }

    @Override
    public StarMonthlySettlementDetailVO detail(Long id) {
        StarMonthlySettlement starMonthlySettlement = this.getSettlement(id, true);
        StarMonthlySettlementDetailVO detailVO = new StarMonthlySettlementDetailVO();
        BeanUtils.copyProperties(starMonthlySettlement, detailVO);
        //审批流信息
        Long flowId = approvalFlowService.getFlowId(id, ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId());
        if (Objects.nonNull(flowId)) {
            detailVO.setFlowId(flowId);
            List<Long> flowList = new ArrayList<>(Collections.singletonList(flowId));
            JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
            detailVO.setFlowStatusName(CommonUtil.defaultString(flowMapping, detailVO.getFlowId()));
        }
        String stringFlowIds = approvalFlowService.getStringFlowIds(id, ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId());
        detailVO.setFlowIds(stringFlowIds);
        //获取红人昵称
        StarBasicData starBasicData = starBasicDataMapper.selectById(detailVO.getStarId());
        BusinessAssert.notNull(starBasicData, McnErrorCode.STAR_BASIC_DATA_IS_NULL);
        detailVO.setStarNickname(starBasicData.getStarNickname());
        detailVO.setStarType(starBasicData.getStarType());
        ////获取账户信息
        StarSettlementAccountInfoVO starAccountInfoVO = new StarSettlementAccountInfoVO();
        if (Objects.nonNull(starMonthlySettlement.getStarAccountId())) {
            StarAccountInfo starAccountInfo = starAccountInfoService.getById(starMonthlySettlement.getStarAccountId());
            BusinessAssert.notNull(starAccountInfo, McnErrorCode.STAR_ACCOUNT_BASIC_DATA_IS_NULL);
            starAccountInfoVO.setAccountName(starAccountInfo.getAccountName());
            starAccountInfoVO.setStudioPayment(starAccountInfo.getStudioPayment());
            starAccountInfoVO.setAccountType(starAccountInfo.getAccountType());
            starAccountInfoVO.setAccountNumber(starAccountInfo.getAccountNumber());
            starAccountInfoVO.setAccountBranchBank(starAccountInfo.getAccountBranchBank());
            starAccountInfoVO.setAccountBank(starAccountInfo.getAccountBank());
            starAccountInfoVO.setAccountIdCard(starAccountInfo.getAccountIdCard());
            starAccountInfoVO.setAccountPhone(starAccountInfo.getAccountPhone());
            starAccountInfoVO.setAccountCity(starAccountInfo.getAccountCity());
            starAccountInfoVO.setAccountProvince(starAccountInfo.getAccountProvince());
        }
        detailVO.setStarAccountInfoVO(starAccountInfoVO);
        //查询所属部门名称
        Map<Long, SDepartment> sDepartmentMap = privilegeClient.getDepartmentByIds(Collections.singletonList(detailVO.getDepartmentId())).getObj();
        if (CommonUtil.containsKey(sDepartmentMap, detailVO.getDepartmentId())) {
            detailVO.setDepartmentName(sDepartmentMap.get(detailVO.getDepartmentId()).getDepartmentName());
        }
        //查询子结算单
        List<StarMonthlySettlementSub> subSettlementList = settlementSubMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .eq(StarMonthlySettlementSub::getSettlementId, detailVO.getId())
                .eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO));
        if (CollectionUtils.isNotEmpty(subSettlementList)) {
            List<FinanceInvoiceDTO> financeInvoiceDTOList = RpcUtil.getObjException(financeClient.getMcnInvoice(starMonthlySettlement.getSettlementCode()), "查询财务账单信息失败");
            Map<String, FinanceInvoiceDTO> invoiceMap = CommonUtil.defaultList(financeInvoiceDTOList).stream()
                    .filter(e -> StringUtils.isNotBlank(e.getChargeSourceDetail())).collect(Collectors.toMap(k -> k.getChargeSourceDetail(), v -> v));
            //查询我司签约主体名称
            List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
            Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
            List<StarMonthlySettlementSubVO> subSettlementInfoList = subSettlementList.stream().map(subSettlement -> {
                StarMonthlySettlementSubVO subVO = new StarMonthlySettlementSubVO();
                BeanUtils.copyProperties(subSettlement, subVO);
                if (invoiceMap.containsKey(subVO.getSubSettlementCode())) {
                    FinanceInvoiceDTO financeInvoiceDTO = invoiceMap.get(subVO.getSubSettlementCode());
                    subVO.setFinanceBillId(financeInvoiceDTO.getInvoiceId());
                    subVO.setFinanceBillNo(financeInvoiceDTO.getInvoiceNo());
                }
                subVO.setCompanyContractSubject(companyMap.get(subVO.getContractingId()));
                return subVO;
            }).collect(Collectors.toList());
            detailVO.setSubSettlementList(subSettlementInfoList);
        }


        //查询执行单信息
        List<Long> excutionOrderIds = CommonUtil.defaultList(settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .select(StarMonthlySettlementDetail::getExcutionOrderId).eq(StarMonthlySettlementDetail::getSettlementId, id)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO).eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)))
                .stream().map(StarMonthlySettlementDetail::getExcutionOrderId).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(excutionOrderIds)){
            List<ContractExcutionOrder> executionOrders = excutionOrderMapper.selectBatchIds(excutionOrderIds);

            Set<Long> customerIdList = new HashSet<>();
            executionOrders.forEach(e -> {
                customerIdList.add(e.getCustomerId());
            });

            //查询执行单客户信息
            Map<Long, BaseCustomer> baseCustomerMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(customerIdList)) {
                baseCustomerMap = Optional.ofNullable(baseInfoClient.getMcnCustomerByIds(new ArrayList<>(customerIdList))).map(x -> x.getObj()).orElse(Collections.EMPTY_MAP);
            }
            //查询红人信息
            List<BasicExcutionOrderVO> excutionOrdersVOs = contractExcutionOrderService.basicExcutionOrderList(executionOrders);

            //查询意向单
            List<String> excuteCodes = executionOrders.stream().map(x -> x.getExcuteCode()).collect(Collectors.toList());
            Map<String, DocIntentionOrder> intentionOrderMap = new HashMap<>();
            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(excuteCodes)) {
                List<DocIntentionOrder> docIntentionOrders = intentionOrderMapper.selectList(new QueryWrapper<DocIntentionOrder>().lambda().in(DocIntentionOrder::getExcutionOrderCode, excuteCodes));
                intentionOrderMap = docIntentionOrders.stream().collect(Collectors.toMap(DocIntentionOrder::getExcutionOrderCode, x -> x, (x, y) -> x));
            }

            Map<Long, BaseCustomer> finalBaseCustomerMap = baseCustomerMap;
            Map<String, DocIntentionOrder> finalIntentionOrderMap = intentionOrderMap;
            excutionOrdersVOs.forEach(e -> {
                BaseCustomer customer = finalBaseCustomerMap.get(e.getCustomerId());
                if (Objects.nonNull(customer)) {
                    e.setCustomerId(customer.getCustomerId());
                    e.setCustomerName(customer.getCustomerNameC());
                    e.setCustomerCode(customer.getCustomerCode());
                }
                e.setPlatformOrderNumber(e.getPlatformOrderCode());
                e.setIntentionOrderId(Optional.ofNullable(finalIntentionOrderMap.get(e.getExcuteCode())).map(x -> x.getId()).orElse(null));
            });
            detailVO.setExcutionOrdersVOs(excutionOrdersVOs);
        }
        return detailVO;
    }

    @Override
    public KVPair<String, List<StatementPerformListExportVO>> exportSubSettlement(Long id) {
        StarMonthlySettlementSub starMonthlySettlementSub = this.getSettlementSub(id, true);
        //查询我司签约主体名称
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
        List<StatementPerformListExportVO> subList = CommonUtil.defaultList(settlementDetailMapper.exportSubSettlementList(id,starMonthlySettlementSub.getSubSettlementCode()));
        if (CollectionUtils.isNotEmpty(subList)) {
            initRecord(subList, companyMap);
        }
        String tabName = companyMap.get(starMonthlySettlementSub.getContractingId());
        return new KVPair<>(StringUtils.defaultIfBlank(tabName, "未知"), subList);
    }

    @Override
    public List<StarMonthlySettlementDetailExportVO> exportSettlementDetail(StarMonthlySettlementDetailQueryDTO queryDTO) {
        List<StarMonthlySettlementDetailExportVO> offlineList = CommonUtil.defaultList(settlementDetailMapper.exportSettlementDetail(queryDTO));
        if (CollectionUtils.isNotEmpty(offlineList)) {
            List<String> brandCodes = offlineList.stream().map(StarMonthlySettlementDetailExportVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            offlineList.forEach(e -> {
                e.setExcuteOrderStatusName(ExcutionApprovalStatusEnum.getStatusName(e.getExcuteOrderStatus()));
                if(brandMap.containsKey(e.getBrandName())) {
                    e.setBrandName(brandMap.get(e.getBrandName()));
                }
            });
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(
                    DictStream.map("Release_type", StarMonthlySettlementDetailExportVO::getPublishType, StarMonthlySettlementDetailExportVO::setPublishType)
                    ), (dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                            .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                    offlineList);
        }
        return offlineList;
    }

    /**
     * 红人月度结算单-导出结算单明细 修改后版本
     *
     * @param queryDTO 查询条件
     * @return
     */
    @Override
    public List<StatementPerformListExportVO> exportSettlementDetailList(StarMonthlySettlementDetailQueryDTO queryDTO) {
        List<StatementPerformListExportVO> offlineList = CommonUtil.defaultList(settlementDetailMapper.exportSettlementDetailList(queryDTO));
        if (CollectionUtils.isNotEmpty(offlineList)) {
            initExportDetailList(offlineList);
        }
        return offlineList;
    }

    /**
     * 初始化导出列表信息
     * @param offlineList
     */
    private void initExportDetailList(List<StatementPerformListExportVO> offlineList) {
        //查询我司签约主体
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
        initRecord(offlineList, companyMap);
    }

    private void initRecord(List<StatementPerformListExportVO> offlineList, Map<Long, String> companyMap) {
        //获取审批流ID
        List<Long> idList = offlineList.stream().map(StatementPerformListExportVO::getId).collect(Collectors.toList());
        Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, Collections.singletonList(ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId()));
        List<String> brandCodes = offlineList.stream().map(StatementPerformListExportVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
        //发布平台信息获取
        Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
        offlineList.forEach(off -> {
            off.setExcuteOrderStatusName(ExcutionApprovalStatusEnum.getStatusName(off.getExcuteOrderStatus()));
            if (MapUtils.isNotEmpty(flowMap)) {
                off.setFlowId(flowMap.get(off.getId()));
            }
            if(brandMap.containsKey(off.getBrandName())) {
                off.setBrandName(brandMap.get(off.getBrandName()));
            }
            if (MapUtils.isNotEmpty(companyMap)) {
                String companyContractSubject = companyMap.get(off.getContractingId());
                off.setCompanyContractSubject(companyContractSubject);
            }
            if(StrUtil.isNotBlank(off.getPublishForm())&&StrUtil.isNotBlank(off.getPlatformId())){
                off.setPublishForm(CommonUtil.getMapValue(secondlevelDictMap.get(off.getPlatformId()), off.getPublishForm()));
            }
        });
        //获取审批流名称
        List<Long> flowList = offlineList.stream().map(StatementPerformListExportVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
        JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
        offlineList.forEach(item -> {
            item.setFlowStatusName(CommonUtil.defaultString(flowMapping, item.getFlowId()));
        });
        //字典翻译
        DictTranslationUtils.translation(() -> DictStream.of(
                        DictStream.map("Release_type", StatementPerformListExportVO::getPublishType, StatementPerformListExportVO::setPublishType)
                ), (dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                        .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                offlineList);
    }

    @Override
    public KVPair<String, List<StarMonthlyOneSettlementExportVO>> exportOneStatement(Long id) {
        StarMonthlySettlement entity = settlementMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlement.class)
                .eq(StarMonthlySettlement::getId, id).eq(StarMonthlySettlement::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "该结算单不存在");
        //获取红人昵称
        StarBasicData starBasicData = starBasicDataMapper.selectById(entity.getStarId());
        BusinessAssert.notNull(starBasicData, McnErrorCode.STAR_BASIC_DATA_IS_NULL);
        String tabName = starBasicData.getStarName() + "-" + entity.getSettlementCode();
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
        List<StarMonthlyOneSettlementExportVO> allSettlementList = CommonUtil.defaultList(settlementDetailMapper.exportOneStatement(id));
        if (CollectionUtils.isNotEmpty(allSettlementList)) {
            List<String> brandCodes = allSettlementList.stream().map(StarMonthlyOneSettlementExportVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            allSettlementList.forEach(sub -> {
                String companyContractSubject = companyMap.get(sub.getContractingId());
                sub.setCompanyContractSubject(companyContractSubject);
                sub.setExcuteOrderStatusName(ExcutionApprovalStatusEnum.getStatusName(sub.getExcuteOrderStatus()));
                if(brandMap.containsKey(sub.getBrandName())) {
                    sub.setBrandName(brandMap.get(sub.getBrandName()));
                }
            });
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(
                    DictStream.map("Release_type", StarMonthlyOneSettlementExportVO::getPublishType, StarMonthlyOneSettlementExportVO::setPublishType)
                    ), (dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                            .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                    allSettlementList);
        }
        return new KVPair<>(StringUtils.defaultIfBlank(tabName, "未知"), allSettlementList);
    }

    @Override
    public KVPair<String, List<StatementListExportVO>> exportStatementList(StarMonthlySettlementSearchDTO searchDTO) {
        searchDTO.setAlias("sms.");
        searchDTO.setProcessIds(Arrays.asList(ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId()));
        if (CollectionUtils.isNotEmpty(searchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(searchDTO.getFlowStatus(), searchDTO.getProcessIds());
            searchDTO.setSrcIds(allList);
        }
        List<StatementListExportVO> statementListExportList = CommonUtil.defaultList(settlementDetailMapper.exportStatementList(searchDTO));
        if (CollectionUtils.isNotEmpty(statementListExportList)) {
            //查询我司签约主体
            List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
            Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
            //获取审批流ID
            List<Long> idList = statementListExportList.stream().map(StatementListExportVO::getId).collect(Collectors.toList());
            Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, searchDTO.getProcessIds());
            statementListExportList.forEach(sub -> {
                if (MapUtils.isNotEmpty(flowMap)) {
                    sub.setFlowId(flowMap.get(sub.getId()));
                }
                if (MapUtils.isNotEmpty(companyMap)) {
                    String companyContractSubject = companyMap.get(sub.getContractingId());
                    sub.setCompanyContractSubject(companyContractSubject);
                }
            });
            //获取审批流名称
            List<Long> flowList = statementListExportList.stream().map(StatementListExportVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
            JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
            statementListExportList.forEach(item -> {
                item.setFlowStatusName(CommonUtil.defaultString(flowMapping, item.getFlowId()));
            });
        }
        return new KVPair<>(StringUtils.defaultIfBlank("红人月度结算单—子结算单", "未知"), statementListExportList);
    }

    @Override
    public KVPair<String, List<StatementPerformListExportVO>> exportStatementPerformList(StarMonthlySettlementSearchDTO searchDTO) {
        searchDTO.setAlias("sms.");
        searchDTO.setProcessIds(Arrays.asList(ApprovalEnum.STAR_MONTHLY_SETTLEMENT.getProcessId()));
        if (CollectionUtils.isNotEmpty(searchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(searchDTO.getFlowStatus(), searchDTO.getProcessIds());
            searchDTO.setSrcIds(allList);
        }
        List<StatementPerformListExportVO> statementPerformList = CommonUtil.defaultList(settlementDetailMapper.exportStatementPerformList(searchDTO));
        if (CollectionUtils.isNotEmpty(statementPerformList)) {


            //查询我司签约主体
            List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
            Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
            initRecord(statementPerformList,companyMap);
        }
        return new KVPair<>(StringUtils.defaultIfBlank("红人月度结算单—执行单", "未知"), statementPerformList);
    }

    /**
     * 获取红人平台信息
     *
     * @param dataList
     * @param platformInfoIdFunc
     * @param <T>
     * @return
     */
    private <T> Map<Long, StarPlatInfoVO> getStarPlatInfoVoMap(List<T> dataList, Function<T, Long> platformInfoIdFunc) {
        //查询红人平台信息
        List<Long> platInfoIds = dataList.stream().map(platformInfoIdFunc).collect(Collectors.toList());
        List<StarPlatInfoVO> starPlatInfoVOList = CommonUtil.defaultList(starPlatformInfoService.getByIds(platInfoIds));
        return starPlatInfoVOList.stream().collect(Collectors.toMap(StarPlatInfoVO::getId, starPlatInfoVO -> starPlatInfoVO));
    }

    /**
     * 获取
     *
     * @param subSettlementCode
     * @return
     */
    @Override
    public StarMonthlySettlementPrintVO getStarMonthlySettlementPrint(String subSettlementCode) {
        StarMonthlySettlementPrintVO starMonthlySettlementPrintVO = settlementDetailMapper.getStarMonthlyPrintStar(subSettlementCode);
        if(Objects.nonNull(starMonthlySettlementPrintVO)) {
            List<StarMonthlySettlementExecuteDataVO> executeDataList = settlementDetailMapper.getExecuteDataList(subSettlementCode);
            /*if(CollectionUtils.isNotEmpty(executeDataList)) {
                executeDataList.forEach(e -> {
                    if(ExcutionOrderTypeEnum.isInside(e.getType()) && SettlementMethodEnum.isBatchRemittance(e.getSettlementMethod())) {
                        e.setDevidedRate(contractExcutionOrderService.getStarDevidedRate(e.getDevidedRateInfo()));
                    }
                });
            }*/
            starMonthlySettlementPrintVO.setExecuteDataList(executeDataList);
            starMonthlySettlementPrintVO.setPaintPaySummaryVO(settlementDetailMapper.getExecuteDataPaySummary(subSettlementCode));
        }
        return starMonthlySettlementPrintVO;
    }

    @Override
    public FinanceSettleInfoVO getFinanceSettleInfo(String chargeSourceCode) {
        FinanceSettleInfoVO financeSettleInfo = settlementDetailMapper.getFinanceSettleInfo(chargeSourceCode);
        BusinessAssert.notNull(financeSettleInfo, McnErrorCode.DATA_NOT_FOUND, "该红人信息不存在");
        return financeSettleInfo;
    }

    @Override
    public StarMonthlySettlementSub getSubSettlementByCode(String subSettlementCode, boolean verifyExist) {
        StarMonthlySettlementSub entity = settlementSubMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .eq(StarMonthlySettlementSub::getSubSettlementCode, subSettlementCode)
                .eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO));
        if (verifyExist) {
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "该子结算单不存在");
        }
        return entity;
    }

    @Override
    public StarMonthlySettlement getSettlementByCode(String settlementCode, boolean verifyExist) {
        StarMonthlySettlement entity = settlementMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlement.class)
                .eq(StarMonthlySettlement::getSettlementCode, settlementCode)
                .eq(StarMonthlySettlement::getIsDelete, NumberCst.ZERO));
        if (verifyExist) {
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "该结算单不存在");
        }
        return entity;
    }

    @Override
    public PaidInfoDetailVO getDefaultPaidInfoByCode(String subSettlementCode) {
        StarMonthlySettlementSub starMonthlySettlementSub = this.getSubSettlementByCode(subSettlementCode, true);
        //开票信息
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(k -> k.getCompanyId(), v -> v.getParentCompanyName()));
        String financeEntity = companyMap.get(starMonthlySettlementSub.getContractingId());
        CompanyNameReq companyNameReq = new CompanyNameReq();
        companyNameReq.setNames(Arrays.asList(financeEntity));
        PaidInfoDetailVO paidInfoDetailVO = new PaidInfoDetailVO();
        paidInfoDetailVO.setTaxInvoiceNo(starMonthlySettlementSub.getInvoiceNo());
        paidInfoDetailVO.setTaxInvoiceDate(starMonthlySettlementSub.getInvoiceDate());
        List<SCompanyBank> sCompanyBanks = privilegeClient.getByCompanyName(companyNameReq).getObj();
        if (CollectionUtils.isNotEmpty(sCompanyBanks)) {
            SCompanyBank sCompanyBank = sCompanyBanks.stream().filter(item -> item.getCompanyName().equals(financeEntity)).findFirst().orElse(null);
            if (sCompanyBank != null) {
                paidInfoDetailVO.setAccountId(sCompanyBank.getCompanyId());
                //'1, "红人收款账户" 2, "客户收款账户" 3, "公司账户" 4, "第三方账户"'
                paidInfoDetailVO.setAccountType(AccountTypeEnum.COMPAY_ACCOUNT.getType());
                //打款方式
                paidInfoDetailVO.setPaidWay(AccountTypeEnum.COMPAY_ACCOUNT.getDesc());
                //开票方式(1=开票、3=后补票)',
                paidInfoDetailVO.setCustomerInvoiceWay(NumberCst.ONE);
                //打款金额
                paidInfoDetailVO.setFinanceDevidedAmount(starMonthlySettlementSub.getFinanceConfirmedDevidedAmount());
                //红人个税
                StarMonthlySettlement starMonthlySettlement = this.getSettlement(starMonthlySettlementSub.getSettlementId(), true);
                StarAccountInfo starAccountInfo = starAccountInfoService.getById(starMonthlySettlement.getStarAccountId());
                if (Objects.nonNull(starAccountInfo)) {
                    paidInfoDetailVO.setTaxRate(starAccountInfo.getTaxRate());
                }
            }
        }
        return paidInfoDetailVO;
    }

    @Override
    public SCompanyBank getScompanyBankByCode(String subSettlementCode) {
        StarMonthlySettlementSub starMonthlySettlementSub = this.getSubSettlementByCode(subSettlementCode, true);
        //开票信息
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(k -> k.getCompanyId(), v -> v.getParentCompanyName()));
        String financeEntity = companyMap.get(starMonthlySettlementSub.getContractingId());
        CompanyNameReq companyNameReq = new CompanyNameReq();
        companyNameReq.setNames(Arrays.asList(financeEntity));
        List<SCompanyBank> sCompanyBanks = privilegeClient.getByCompanyName(companyNameReq).getObj();
        if (CollectionUtils.isEmpty(sCompanyBanks)) {
            return null;
        }
        return sCompanyBanks.stream().filter(item -> item.getCompanyName().equals(financeEntity)).findFirst().orElse(null);
    }

    /**
     * 复制作废的结算单
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long copyInvaild(Long id) {
        StarMonthlySettlement settlement = this.getSettlement(id, true);
        BusinessAssert.isTrue(StarMonthlySettlementStatusEnum.isInvalid(settlement.getApprovalStatus()), McnErrorCode.BUSINESS_ERROR, "非作废的结算单不允许复制");
        StarMonthlySettlement newSettlement = new StarMonthlySettlement();
        newSettlement.setStarId(settlement.getStarId());
        newSettlement.setSettlementCode(CodeGenerateHelper.getCode(BillCodeCst.STAR_MONTHLY_SETTLEMENT));
        newSettlement.setApprovalStatus(StarMonthlySettlementStatusEnum.UN_COMMIT.getCode());
        newSettlement.setAttachmentFile(settlement.getAttachmentFile());
        newSettlement.setConfirmScreenshot(settlement.getConfirmScreenshot());
        newSettlement.setSettlementDate(settlement.getSettlementDate());
        newSettlement.setIsOfflineReimburse(ObjectUtils.defaultIfNull(settlement.getIsOfflineReimburse(), NumberCst.ZERO));
        newSettlement.setStarAccountId(settlement.getStarAccountId());
        newSettlement.setRemark(settlement.getRemark());
        boolean result = settlementMapper.insert(newSettlement) > 0;
        if (result) {
            List<StarMonthlySettlementDetail> detailList = CommonUtil.defaultList(settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                    .eq(StarMonthlySettlementDetail::getSettlementId, settlement.getId())
                    .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ONE)
                    .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)));
            List<Long> excutionOrderIds = detailList.stream().map(StarMonthlySettlementDetail::getExcutionOrderId).distinct().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(excutionOrderIds)) {
                StarMonthlySettlementDetailAddDTO detailAddDTO = new StarMonthlySettlementDetailAddDTO();
                detailAddDTO.setSettlementId(newSettlement.getId());
                detailAddDTO.setExcutionOrderIds(excutionOrderIds);
                Map<Long, StarMonthlySettlementDetail> detailMap = detailList.stream().collect(Collectors.toMap(k -> k.getExcutionOrderId(), v -> v));
                this.addDetailsIfNecessary(newSettlement, detailAddDTO, detailMap, true);
            }
        }
        return newSettlement.getId();
    }

    @Override
    public StarMonthlySettlement getSettlementByExcuteId(Long excuteId) {
        StarMonthlySettlementDetail settlementDetail = settlementDetailMapper.selectOne(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .eq(StarMonthlySettlementDetail::getExcutionOrderId, excuteId)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)
                .last(" limit 1"));
        if(Objects.nonNull(settlementDetail)) {
            return settlementMapper.selectById(settlementDetail.getSettlementId());
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void confirmPayment(List<Long> ids) {
        List<StarMonthlySettlementDetail> settlementDetails = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .in(StarMonthlySettlementDetail::getId, ids)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)
                .isNull(StarMonthlySettlementDetail::getSubSettlementId));
        BusinessAssert.notEmpty(settlementDetails, McnErrorCode.DATA_NOT_FOUND, "线下结算单明细都查不到");
        List<Long> settlementIds = settlementDetails.stream().map(StarMonthlySettlementDetail::getSettlementId).distinct().collect(Collectors.toList());
        BusinessAssert.notEmpty(settlementIds, McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "取消付款只允许在同个红人月度结算单下操作");
        Long settlementId = settlementIds.get(0);
        StarMonthlySettlement settlement = this.getSettlement(settlementId, true);
        DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT.generateKey(settlementId), () -> {
                //执行单置为已打款
                List<Long> excuteIds = settlementDetails.stream().map(StarMonthlySettlementDetail::getExcutionOrderId).distinct().collect(Collectors.toList());
                excutionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(ContractExcutionOrder.class)
                .set(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PAID.getCode())
                .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(ContractExcutionOrder::getUpdateDate, new Date())
                .in(ContractExcutionOrder::getId, excuteIds)
                .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO)
                .eq(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PASSED.getCode()));
                //判断是否全部回款，如果是则更新
                return this.updatePaybackStatus(settlement, false);
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelPayment(List<Long> ids) {
        List<StarMonthlySettlementDetail> settlementDetails = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .in(StarMonthlySettlementDetail::getId, ids)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO)
                .isNull(StarMonthlySettlementDetail::getSubSettlementId));
        BusinessAssert.notEmpty(settlementDetails, McnErrorCode.DATA_NOT_FOUND, "线下结算单明细都查不到");
        List<Long> settlementIds = settlementDetails.stream().map(StarMonthlySettlementDetail::getSettlementId).distinct().collect(Collectors.toList());
        BusinessAssert.notEmpty(settlementIds, McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "取消付款只允许在同个红人月度结算单下操作");
        Long settlementId = settlementIds.get(0);
        DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT.generateKey(settlementId),
            () -> {
                //解除关联
                settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                        .set(StarMonthlySettlementDetail::getIsDelete, NumberCst.ONE)
                        .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                        .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                        .in(StarMonthlySettlementDetail::getId, settlementDetails.stream().map(StarMonthlySettlementDetail::getId).collect(Collectors.toList())));
                StarMonthlySettlement settlement = this.getSettlement(settlementId, true);
                StarMonthlySettlement newStarMonthlySettlement = new StarMonthlySettlement();
                newStarMonthlySettlement.setId(settlementId);
                settlementMapper.updateById(newStarMonthlySettlement);
                return this.updatePaybackStatus(settlement, false);
            });
    }

    /**
     * 校验单据状态
     *
     * @param starMonthlySettlement
     */
    private void verifyApprovalStatus(StarMonthlySettlement starMonthlySettlement) {
        if (starMonthlySettlement.getApprovalStatus() != StarMonthlySettlementStatusEnum.UN_COMMIT.getCode() &&
                starMonthlySettlement.getApprovalStatus() != StarMonthlySettlementStatusEnum.REJECTED.getCode() &&
                starMonthlySettlement.getApprovalStatus() != StarMonthlySettlementStatusEnum.CANCEL.getCode()) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVA_UPDATE_ERROR);
        }
    }

    /**
     * 结算单-拆单
     *
     * @param starMonthlySettlement
     * @return
     */
    private void splitSettlement(StarMonthlySettlement starMonthlySettlement) {
        //删除之前的拆单信息
        this.deletePreviousSplit(starMonthlySettlement);
        //拆单
        List<StarMonthlySettlementDetail> detailList = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId())
                .eq(StarMonthlySettlementDetail::getSettlementForm, NumberCst.ZERO)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO));
        if (CollectionUtils.isEmpty(detailList)) {
            return;
        }
        StarAccountInfo starAccountInfo = starAccountInfoService.getById(starMonthlySettlement.getStarAccountId());
        BusinessAssert.notNull(starAccountInfo, McnErrorCode.BUSINESS_ERROR, "查询不到该红人收款账号信息！");
        Map<Long, List<StarMonthlySettlementDetail>> detailMap = detailList.stream().collect(Collectors.groupingBy(StarMonthlySettlementDetail::getContractingId));
        for (Map.Entry<Long, List<StarMonthlySettlementDetail>> entry : detailMap.entrySet()) {
            Long contractingId = entry.getKey();
            List<StarMonthlySettlementDetail> subDetailList = entry.getValue();
            BigDecimal pretaxAmount = subDetailList.stream().map(StarMonthlySettlementDetail::getFinanceDevidedAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal financeCulturalTax = subDetailList.stream().map(StarMonthlySettlementDetail::getFinanceCulturalTax).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            StarMonthlySettlementSub subSettlement = new StarMonthlySettlementSub();
            subSettlement.setSettlementId(starMonthlySettlement.getId());
            subSettlement.setSubSettlementCode(CodeGenerateHelper.getCode(BillCodeCst.STAR_MONTHLY_SETTLEMENT_SUB));
            subSettlement.setContractingId(contractingId);
            subSettlement.setPretaxAmount(pretaxAmount);
            subSettlement.setAfterCulturalTaxDivided(pretaxAmount.subtract(financeCulturalTax));
            subSettlement.setTaxableAmount(StudioPaymentEnum.isCompany(starAccountInfo.getStudioPayment()) ? BigDecimal.ZERO : null);
            boolean result = settlementSubMapper.insert(subSettlement) > 0;
            if (result) {
                List<Long> subDetailIds = subDetailList.stream().map(StarMonthlySettlementDetail::getId).collect(Collectors.toList());
                settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                        .set(StarMonthlySettlementDetail::getSubSettlementId, subSettlement.getId())
                        .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                        .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                        .in(StarMonthlySettlementDetail::getId, subDetailIds));
            }
        }
    }

    /**
     * 删除之前拆单信息
     *
     * @param starMonthlySettlement
     * @return
     */
    private void deletePreviousSplit(StarMonthlySettlement starMonthlySettlement) {
        //判断是否存在子结算单
        boolean existed = settlementSubMapper.exist(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .eq(StarMonthlySettlementSub::getSettlementId, starMonthlySettlement.getId())
                .eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO));
        if (!existed) {
            return;
        }
        //删除子结算单
        boolean result = settlementSubMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementSub.class)
                .set(StarMonthlySettlementSub::getIsDelete, NumberCst.ONE)
                .set(StarMonthlySettlementSub::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlementSub::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlementSub::getUpdateDate, new Date())
                .eq(StarMonthlySettlementSub::getSettlementId, starMonthlySettlement.getId()));
        if (result) {
            //子结算单解绑明细
            settlementDetailMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlementDetail.class)
                    .set(StarMonthlySettlementDetail::getSubSettlementId, null)
                    .set(StarMonthlySettlementDetail::getShareTaxAmount, null)
                    .set(StarMonthlySettlementDetail::getAftertaxShareAmount, null)
                    .set(StarMonthlySettlementDetail::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(StarMonthlySettlementDetail::getUpdateName, UserVoContextHolder.getUserName())
                    .set(StarMonthlySettlementDetail::getUpdateDate, new Date())
                    .eq(StarMonthlySettlementDetail::getSettlementId, starMonthlySettlement.getId()));
        }
    }

    /**
     * 关联待打款的执行单-置为已打款
     *
     * @param settlement
     * @param approvalStatus
     */
    private void updateExcutionOrderStatusIfNecessary(StarMonthlySettlement settlement, StarMonthlySettlementSub subSettlement, Integer approvalStatus, boolean rollback) {
        //红人月度结算单已回款后，关联待打款的执行单-置为已打款
        List<StarMonthlySettlementDetail> detailList = null;
        Long subSettlementId = Objects.nonNull(subSettlement) ? subSettlement.getId() : null;
        Date paidDate = Objects.nonNull(subSettlement) ? subSettlement.getPaidDate() : null;
        if (StarMonthlySettlementStatusEnum.anyMatch(approvalStatus, StarMonthlySettlementStatusEnum.ALL_PAYBACK, StarMonthlySettlementStatusEnum.PART_PAYBACK)) {
            detailList = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                    .select(StarMonthlySettlementDetail::getExcutionOrderId)
                    .eq(StarMonthlySettlementDetail::getSettlementId, settlement.getId())
                    .eq(Objects.nonNull(subSettlementId), StarMonthlySettlementDetail::getSubSettlementId, subSettlementId)
                    .eq(StarMonthlySettlementDetail::getSettlementForm, NumberCst.ZERO)
                    .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                    .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO));
        }
        if (CollectionUtils.isEmpty(detailList)) {
            return;
        }
        List<Long> excutionOrderIds = detailList.stream().map(StarMonthlySettlementDetail::getExcutionOrderId).distinct().collect(Collectors.toList());
        List<ContractExcutionOrder> excutionOrderList = CommonUtil.partitionList(excutionOrderIds, McnConstant.MAX_INSERT_SIZE, (ids) -> excutionOrderMapper.selectBatchIds(ids));
        if(CollectionUtils.isEmpty(excutionOrderList)) {
            return;
        }
        //按大小50的维度拆分List  注：如果ID多的话，则改DB执行
        Lists.partition(excutionOrderIds, McnConstant.MAX_INSERT_SIZE).forEach(ids -> {
            excutionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(ContractExcutionOrder.class)
                    .set(ContractExcutionOrder::getApprovalStatus, rollback ? ExcutionApprovalStatusEnum.PASSED.getCode() : ExcutionApprovalStatusEnum.PAID.getCode())
                    .set(Objects.nonNull(paidDate), ContractExcutionOrder::getPaidStarDate, paidDate)
                    .set(ContractExcutionOrder::getUpdateBy, settlement.getUpdateBy())
                    .set(ContractExcutionOrder::getUpdateName, settlement.getUpdateName())
                    .set(ContractExcutionOrder::getUpdateDate, settlement.getUpdateDate())
                    .in(ContractExcutionOrder::getId, ids)
                    .eq(ContractExcutionOrder::getApprovalStatus, rollback ? ExcutionApprovalStatusEnum.PAID.getCode() : ExcutionApprovalStatusEnum.PASSED.getCode())
            );
        });
        //发送执行单-日志
        Map<Long, ContractExcutionOrder> excutionOrderMap = excutionOrderList.stream().collect(Collectors.toMap(k -> k.getId(), v -> v));
        for(Map.Entry<Long, ContractExcutionOrder> entry : excutionOrderMap.entrySet()) {
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(entry.getKey())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(entry.getValue(), excutionOrderMapper.selectById(entry.getKey()))
                    .build());
        }
    }

    /**
     * 按需添加红人月度结算单明细
     *
     * @param starMonthlySettlement
     * @param dto
     * @param detailMap
     * @return
     */
    private boolean addDetailsIfNecessary(StarMonthlySettlement starMonthlySettlement, StarMonthlySettlementDetailAddDTO dto, Map<Long, StarMonthlySettlementDetail> detailMap,
                                          boolean logEnable) {
        return DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT_STARID.generateKey(starMonthlySettlement.getStarId()),
                () -> {
                    // 查询有效关联的执行单
                    StarMonthlySettlementExcutionOrderAddDTO addDTO = new StarMonthlySettlementExcutionOrderAddDTO();
                    addDTO.setStarId(starMonthlySettlement.getStarId());
                    addDTO.setApprovalStatus(ExcutionApprovalStatusEnum.PASSED.getCode());
                    addDTO.setSettlementMethod(SettlementMethodEnum.BATCH_REMITTANCE.getCode());
                    addDTO.setExcutionOrderIds(dto.getExcutionOrderIds());
                    List<StarMonthlySettlementExcutionOrderAddVO> excutionOrderList = settlementDetailMapper.getAddExcutionOrders(addDTO);
                    if (MapUtils.isEmpty(detailMap)) {
                        BusinessAssert.notEmpty(excutionOrderList, McnErrorCode.DATA_NOT_FOUND, "无有效关联的执行单");
                    }
                    boolean result = false;
                    if (CollectionUtils.isNotEmpty(excutionOrderList)) {
                        List<StarMonthlySettlementDetail> detailList = new ArrayList<>(excutionOrderList.size());
                        excutionOrderList.forEach(excutionOrder -> {
                            StarMonthlySettlementDetail detail = new StarMonthlySettlementDetail();
                            detail.setSettlementId(starMonthlySettlement.getId());
                            detail.setExcutionOrderId(excutionOrder.getId());
                            String errorSubffix = "执行单编号=" + excutionOrder.getIncomeContractCode();
                            BusinessAssert.notNull(excutionOrder.getContractingId(), McnErrorCode.PARAM_ERROR, "我司签约主体不能为空！" + errorSubffix);
                            detail.setContractingId(excutionOrder.getContractingId());
                            BusinessAssert.notNull(excutionOrder.getFinanceDevidedAmount(), McnErrorCode.PARAM_ERROR, "财务确认分成金额不能为空！" + errorSubffix);
                            detail.setFinanceDevidedAmount(excutionOrder.getFinanceDevidedAmount());
                            detail.setFinanceCulturalTax(excutionOrder.getFinanceCulturalTax());
                            BusinessAssert.notNull(excutionOrder.getSettlementForm(), McnErrorCode.PARAM_ERROR, "结算形式不能为空！" + errorSubffix);
                            if (MapUtils.isEmpty(detailMap) || !detailMap.containsKey(excutionOrder.getId())) {
                                detail.setSettlementForm(excutionOrder.getSettlementForm());
                            } else {
                                StarMonthlySettlementDetail oldDetail = detailMap.get(excutionOrder.getId());
                                detail.setSettlementForm(oldDetail.getSettlementForm());
                                detail.setRemark(oldDetail.getRemark());
                            }
                            detail.setIsInvalid(NumberCst.ZERO);
                            detailList.add(detail);
                        });
                        result = settlementDetailMapper.insertBatch(detailList) > 0;
                        if (result) {
                            
                            StarMonthlySettlement newStarMonthlySettlement = settlementMapper.selectById(starMonthlySettlement.getId());;
                            if (logEnable) {
                                EventPublisher.post(OperateLogEvent.builder().businessId(starMonthlySettlement.getId())
                                        .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                                        .compare(starMonthlySettlement, newStarMonthlySettlement)
                                        .build());
                            }
                        }
                    }
                    return result;
                });
    }

    /**
     * 更新财务可确认分成金额明细
     *
     * @param settlementId
     * @param isClear 是否置空
     */
    private void updateFinanceConfirmedDevidedAmountDetail(Long settlementId, boolean isClear) {
        Map<Long, StarMonthlySettlementSub> oldSubMap = CommonUtil.defaultList(settlementSubMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementSub.class)
                .eq(StarMonthlySettlementSub::getSettlementId, settlementId).eq(StarMonthlySettlementSub::getIsDelete, NumberCst.ZERO)
        )).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
        settlementSubMapper.updateFinanceConfirmedDevidedAmountDetail(settlementId, isClear);
        if(MapUtils.isNotEmpty(oldSubMap)) {
            this.sendBatchLog(settlementId, oldSubMap);
        }
    }

    /**
     * 更改关联的执行单-结算形式
     *
     * @param settlement
     */
    private void updateSettlementFormOfExcutionOrder(StarMonthlySettlement settlement) {
        //红人月度结算单已回款后，关联待打款的执行单-置为已打款
        List<StarMonthlySettlementDetail> detailList = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .select(StarMonthlySettlementDetail::getExcutionOrderId, StarMonthlySettlementDetail::getSettlementForm)
                .eq(StarMonthlySettlementDetail::getSettlementId, settlement.getId())
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO));
        if (CollectionUtils.isEmpty(detailList)) {
            return;
        }
        detailList.forEach(e -> {
            //加锁
            calculationDevidedMapper.updateByNoStrategy(Wrappers.lambdaUpdate(CalculationDevided.class)
                    .set(CalculationDevided::getSettlementForm, e.getSettlementForm())
                    .set(CalculationDevided::getUpdateBy, settlement.getUpdateBy())
                    .set(CalculationDevided::getUpdateName, settlement.getUpdateName())
                    .set(CalculationDevided::getUpdateDate, settlement.getUpdateDate())
                    .eq(CalculationDevided::getExcutionOrderId, e.getExcutionOrderId())
                    .eq(CalculationDevided::getIsDelete, NumberCst.ZERO));
        });
    }

    /**
     * 判断结算单下所有执行单是否都已打款
     * @return
     */
    private boolean updatePaybackStatus(StarMonthlySettlement settlement, boolean isOnline) {
        Long settlementId = settlement.getId();
        List<StarMonthlySettlementDetail> detailList = settlementDetailMapper.selectList(Wrappers.lambdaQuery(StarMonthlySettlementDetail.class)
                .select(StarMonthlySettlementDetail::getExcutionOrderId, StarMonthlySettlementDetail::getSettlementForm)
                .eq(StarMonthlySettlementDetail::getSettlementId, settlementId)
                .eq(StarMonthlySettlementDetail::getIsInvalid, NumberCst.ZERO)
                .eq(StarMonthlySettlementDetail::getIsDelete, NumberCst.ZERO));
        if(CollectionUtils.isEmpty(detailList)) {
            return settlementMapper.updateByNoStrategy(Wrappers.lambdaUpdate(StarMonthlySettlement.class)
                    .set(StarMonthlySettlement::getApprovalStatus, StarMonthlySettlementStatusEnum.ALL_PAYBACK.getCode())
                    .set(StarMonthlySettlement::getOnlinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode())
                    .set(StarMonthlySettlement::getOfflinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode())
                    .set(StarMonthlySettlement::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(StarMonthlySettlement::getUpdateName, UserVoContextHolder.getUserName())
                    .set(StarMonthlySettlement::getUpdateDate, new Date())
                    .eq(StarMonthlySettlement::getId, settlementId));
        }
        List<Long> excuteIds = detailList.stream().map(StarMonthlySettlementDetail::getExcutionOrderId).distinct().collect(Collectors.toList());
        //判断是否全部回款，如果是则更新
        List<ContractExcutionOrder> unPaidExcutionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getId, excuteIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO)
                .notIn(ContractExcutionOrder::getApprovalStatus, Arrays.asList(ExcutionApprovalStatusEnum.PAID.getCode(), ExcutionApprovalStatusEnum.INVALID.getCode())));
        LambdaUpdateWrapper<StarMonthlySettlement> lambdaUpdateWrapper = Wrappers.lambdaUpdate(StarMonthlySettlement.class);
        if(CollectionUtils.isEmpty(unPaidExcutionOrders)) {
            lambdaUpdateWrapper.set(StarMonthlySettlement::getApprovalStatus, StarMonthlySettlementStatusEnum.ALL_PAYBACK.getCode())
                    .set(StarMonthlySettlement::getOnlinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode())
                    .set(StarMonthlySettlement::getOfflinePaidStatus, PaidStatusEnum.ALL_PAYBACK.getCode());
        } else {
            lambdaUpdateWrapper.set(StarMonthlySettlement::getApprovalStatus, StarMonthlySettlementStatusEnum.PART_PAYBACK.getCode());
            List<Long> unPaidExcuteIds = unPaidExcutionOrders.stream().map(ContractExcutionOrder::getId).distinct().collect(Collectors.toList());
            Map<Integer, List<Long>> unPaidFormMap = detailList.stream().filter(e -> unPaidExcuteIds.contains(e.getExcutionOrderId())).collect(Collectors.groupingBy(StarMonthlySettlementDetail::getSettlementForm,
                    Collectors.mapping(StarMonthlySettlementDetail::getExcutionOrderId, Collectors.toList())));
            if(isOnline) {
                lambdaUpdateWrapper.set(StarMonthlySettlement::getOnlinePaidStatus, unPaidFormMap.containsKey(NumberCst.ZERO) ? PaidStatusEnum.PART_PAYBACK.getCode() : PaidStatusEnum.ALL_PAYBACK.getCode());
            } else {
                lambdaUpdateWrapper.set(StarMonthlySettlement::getOfflinePaidStatus, unPaidFormMap.containsKey(NumberCst.ONE) ? PaidStatusEnum.PART_PAYBACK.getCode() : PaidStatusEnum.ALL_PAYBACK.getCode());
            }
        }
        settlementMapper.updateByNoStrategy(lambdaUpdateWrapper
                .set(StarMonthlySettlement::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarMonthlySettlement::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarMonthlySettlement::getUpdateDate, new Date())
                .eq(StarMonthlySettlement::getId, settlementId));
        //操作日志-结算单
        EventPublisher.post(OperateLogEvent.builder().businessId(settlement.getId())
                .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                .compare(settlement, settlementMapper.selectById(settlement.getId()))
                .build());
        return true;
    }

    /**
     *
     * @param settlementId
     * @param oldSubMap
     */
    private void sendBatchLog(Long settlementId, Map<Long, StarMonthlySettlementSub> oldSubMap) {
        Map<Long, StarMonthlySettlementSub> newSubMap = CommonUtil.defaultList(settlementSubMapper.selectBatchIds(oldSubMap.keySet())).stream().collect(Collectors.toMap(StarMonthlySettlementSub::getId, Function.identity()));
        for(Map.Entry<Long, StarMonthlySettlementSub> entry : oldSubMap.entrySet()) {
            if(!newSubMap.containsKey(entry.getKey())) {
                continue;
            }
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(settlementId)
                    .businessType(LogBusinessTypeEnum.STAR_MONTHLY_SETTLEMENT)
                    .compare(entry.getValue(), newSubMap.get(entry.getKey())).build());
        }
    }
}
